Jeden hárok máte postavený presne správne. Pás hlavičky je zlúčený, šírky stĺpcov sedia na dáta, horné dva riadky sú zmrazené, oblasť tlače a okraje sú nastavené na čistý export A4 a karta je zafarbená, aby ju financie ľahko našli. Teraz report potrebuje dvanásť takýchto hárkov, jeden pre každý región, každý začínajúci z rovnakého rozloženia. Znovu budovať ten istý hárok v kóde dvanásťkrát je presne spôsob, ako sa doň vkradne jemný drift: región 7 dostane jeden stĺpec o bod užší, región 11 príde o zmrazenie a nik si to nevšimne, kým PDF nepristane na stole manažéra. To, čo skutočne chcete, je programová verzia pravého kliku v Exceli, Move or Copy, Create a copy: vziať hotový hárok a raziť z neho nezávislé duplikáty
XLSX engine v HotXLS, natívnej knižnici pre Delphi a C++Builder, ktorá číta a zapisuje súbory Excelu bez automatizácie Excelu, už vedel presúvať hárky, mazať ich a kopírovať rozsahy buniek medzi hárkami. Až do verzie v2.91.0 však nevedel naklonovať celý pracovný hárok jedným volaním. Táto verzia pridáva dva vstupné body: TXLSXWorksheet.CopyFrom, ktorý kopíruje stav na úrovni hárka z jedného worksheetu na druhý, a TXLSXSheets.Duplicate, ktorý pridá nový hárok a spustí za vás CopyFrom. Zaujímavé nie je to, že kopíruje veci. Dôležitá je vedomá hranica medzi tým, čo sa kopíruje do hĺbky a čo nie, a prečo je nakreslená práve tam
Jedno volanie na klonovanie hotového hárka
Operáciou na vysokej úrovni je Duplicate. Odovzdáte jej 1-based index zdrojového hárka a ona vráti úplne nový worksheet, ktorý zrkadlí rozloženie a dáta originálu. Konvencia indexov zodpovedá Items[] na strane XLSX, takže prvý hárok má index 1, nie 0; ak odovzdáte index mimo rozsahu, dostanete nil namiesto výnimky, ten istý kontrakt zlyhania, aký používa zvyšok kolekcie XLSX hárkov
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;
Pri tej ukážke sa oplatí spomaliť pri dvoch veciach. Po prvé, FreezePanes berie argumenty v poradí row-first, FreezePanes(ARow, ACol), takže ladí s indexovaním Cells[Row, Col]; duplikát zdedí presne ten istý zlom zmrazenia. Po druhé, metóda sa volá Duplicate a nie zdanlivo prirodzenejšie Copy, a to nie je štylistická preferencia. Copy je štandardná rutina v unite System, neustále používaná pre reťazce a dynamické polia. Metóda s názvom Copy na triede by ju vo vnútri metód tienila a vytvorila presne ten druh nejasnosti pri rozlišovaní, ktorý vás uhryzne o šesť mesiacov neskôr. Duplicate sa tejto pasci elegantne vyhne a na mieste volania sa číta správne
Predvolený názov sa riadi rovnakým pravidlom ako v Exceli
Keď zavoláte preťaženie s jedným argumentom alebo odovzdáte prázdny reťazec názvu, nový hárok dostane názov podľa zdroja so suffixom (2) a suffix sa zvyšuje, kým názov nie je jedinečný. Ak raz duplikujete hárok Template, dostanete Template (2); ak ho duplikujete znova, dostanete Template (3), pretože Template (2) je už obsadené. Zodpovedá to názvom, ktoré Excel generuje vlastným príkazom Create a copy, takže workbook vytvorený vaším kódom vyzerá tak, ako by používateľ očakával od ručne duplikovaného zošita. Kontrola jedinečnosti beží nad živou kolekciou hárkov, čo znamená, že preskočí aj názvy, ktoré ste vytvorili ručne, nielen tie z predchádzajúcich duplikácií
Ak generujete jeden hárok na región alebo mesiac, siahnite radšej po preťaženiu s explicitným názvom. Predvídateľná schéma Region-North, Region-South sa neskôr adresuje ľahšie než reťazec suffixov (2), (3) a zároveň udrží definované názvy a medzihárkové vzorce čitateľné
Čo CopyFrom kopíruje do hĺbky
Pod kapotou Duplicate pridá hárok a potom zavolá CopyFrom(ASource), ktoré môžete zavolať aj priamo, keď chcete klonovať do hárka, ktorý ste už vytvorili. CopyFrom hneď na začiatku stráži dva degenerované prípady: kopírovanie z nil, alebo kopírovanie hárka naň samý, v oboch prípadoch okamžite skončí bez vykonania čohokoľvek. Všetko potom je samotná kópia a je zámerne široká
Najprv prídu dáta buniek. CopyFrom si od zdroja vypýta jeho UsedRange, teda tesný ohraničujúci box zaplnených buniek a zlúčených oblastí, a znovu použije existujúci mechanizmus CopyRangeTo, aby preniesol každú hodnotu, vzorec aj index štýlu po bunke do cieľa od A1. Nad bunkami potom znovu prehrá celú vrstvu stavu na úrovni hárka, ktorá robí šablónu hotovou:
- Zlúčené rozsahy, znovu vytvorené podľa súradníc, aby banner pokrýval ten istý obdĺžnik
- Šírky stĺpcov a výšky riadkov spolu so zoznamami hidden, collapsed a outline-level, skopírované doslova, aby nepredvolené riadky a stĺpce sedeli presne
- Freeze panes a stav zobrazenia: úroveň priblíženia, zobrazenie gridlines a nulových hodnôt, smer right-to-left a typ zobrazenia
- Stav ochrany spolu s oprávneniami pre jednotlivé akcie, aby uzamknutá šablóna zostala uzamknutá rovnakým spôsobom
- Celý blok page setupu: okraje, orientácia, veľkosť papiera, mierka a fit-to-page, oblasť tlače, print titles, headers and footers a príznaky print-gridlines a print-headings
- Rozsah AutoFilter, farba karty a viditeľnosť hárka
Výsledkom je hárok, ktorý sa tlačí, filtruje a prezentuje identicky so zdrojom. A keďže bunky, zlúčenia aj zoznamy rozmerov sa na novom hárku fyzicky vytvoria znova namiesto aliasovania, duplikát je úplne nezávislý. Zapíšte 999 do bunky na kópii a zdroj si ponechá pôvodnú hodnotu; táto nezávislosť je najdôležitejšia vlastnosť klonu určeného pre paralelné regionálne reporty a dodaná ukážka SheetCopy ju výslovne overuje
Čo zostáva plytké a prečo
Teraz poctivá časť. Grafy, vložené obrázky, tabuľky XLSX, data validations a pravidlá conditional formatting sa nekopírujú. Je to zdokumentovaná a zámerná hranica, nie prehliadnutie, a stojí za to pochopiť dôvod, aby ste s ňou vedeli plánovať namiesto toho, aby vás prekvapila
Každá z týchto kolekcií nesie identitu a referencie, ktoré naivná kópia polí neprežije. Graf ukazuje na zdrojový dátový rozsah a vlastní drawing relationship v OOXML balíku; klonovanie objektu bez premapovania relationship a referencií sérií vytvorí graf, ktorý sa renderuje nad zlými dátami, alebo balík, ktorý Excel označí ako vyžadujúci opravu. Tabuľka má názov, ktorý musí byť v zošite jedinečný, riadok hlavičky naviazaný na konkrétne stĺpce a vlastný automaticky generovaný relationship. Conditional formats a data validations sa viažu na súradnicové rozsahy a v prípade validation môžu cez vzorce odkazovať na iné rozsahy. Korektne ich skopírovať do hĺbky znamená prepísať referencie a vyraziť nové identity, čo je skutočná práca so skutočnými režimami zlyhania. Urobiť to napoly, teda skopírovať objekt bez jeho referencií, je horšie než nekopírovať vôbec: výsledkom je súbor, ktorý sa otvorí s výzvou na opravu a potichu zahodí obsah. Engine preto kopíruje veci, ktoré vie skopírovať čisto, a kolekcie nesúce referencie necháva na volajúceho, ktorý vie, na čo má cieľ ukazovať
V praxi to znamená, že workflow pre bohatšiu šablónu vyzerá takto: duplikujte hárok, aby ste získali bunky, rozloženie a nastavenie tlače, a potom na kópii znovu vytvorte graf, tabuľku, validations alebo conditional formats tým istým API, ktoré ste použili pri ich prvom vytvorení. Keď ich vytvárate znova nad rozsahmi vlastnej kópie, referencie vyjdú správne už konštrukciou. Pri grafe, ktorý číta A1:C10, pridajte na kópii nový graf ukazujúci na jej vlastné A1:C10; ak chcete živý AutoFilter, všimnite si, že filter rozsah sa prenesie, takže znovu aplikujete len kritériá stĺpcov. Pravidlá conditional formatting a data validation znovu pridáte cez tie isté volania opísané v článku o zlúčených bunkách a rozložení šablón reportov, ktorý prechádza merge table a model rozsahov, ktoré kópia dedí
Kam duplikovanie zapadá v reportovacej pipeline
Duplikovanie worksheetu je prirodzený partner generovania riadeného placeholdermi. Prístup ukotvený na tokenoch v návode na generovanie reportov zo šablón v Delphi rieši problém zapisovania dát do rozloženia, ktoré upravujú iní ľudia; duplikovanie rieši problém, že to isté rozloženie potrebujete mnohokrát v jednom workbooku. Kombináciou oboch je vzor čistý: držte jeden nedotknutý hárok Template so svojimi tokenmi, zlúčeniami a nastavením tlače, potom pre každý región alebo obdobie zavolajte Duplicate, vyplňte tokeny klonu daným výsekom dát a pokračujte ďalej. Pôvodná šablóna sa nikdy neupravuje, takže zostáva spoľahlivým zdrojom pre ďalší klon, a každý výstupný hárok začína z rozloženia identického bajt po bajte
Jedna poznámka k poradiu vás ušetrí celej triedy zmätkov. Hárok duplikujte predtým, než doň nalejete dáta, nie potom. Šablóna má niesť štruktúru a formátovanie, nie čísla z minulého štvrťroka, a klonovanie prázdneho naštýlovaného hárka znamená, že každý duplikát začína čisto. Ak duplikujete hárok, ktorý už dáta obsahuje, tieto dáta sa skopírujú spolu s ním, pretože CopyFrom verne kopíruje použitý rozsah; občas je to presne to, čo chcete, ale pri rozvetvenom reporte zvyčajne nie
Rýchly návyk na verifikáciu
Pretože rozdelenie na deep-copy a shallow-copy je neviditeľné, kým ho cielene nehľadáte, zabudujte si do úlohy päťriadkovú kontrolu namiesto slepej dôvery, že sa prenieslo všetko. Po duplikovaní načítajte späť štrukturálne signály, ktoré má klon dediť, a overte, že sa zhodujú so zdrojom
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.
Počet zlúčení, šírka stĺpca, freeze row a príznak farby karty vám povedia, že vrstva, ktorá sa kopíruje, sa skutočne preniesla. Samostatne pri každom hárku, ktorý niesol graf, tabuľku, validations alebo conditional formats, považujte tieto prvky na kópii za zoznam na znovuvytvorenie: ich neprítomnosť je zámerná a oprava znamená niekoľko volaní, nie bug report. Tento mentálny model, hlboké tam, kde je to bezpečné, a plytké tam, kde by sa referencie lámali, je celý príbeh o tom, ako túto funkciu používať dobre
Duplikovanie worksheetu a kópia stavu hárka cez CopyFrom opísaná tu sa dodávajú vo verzii v2.91.0 natívneho HotXLS Delphi spreadsheet component, spolu so spustiteľnou ukážkou SheetCopy, ktorá kompletný cyklus clone-and-mutate prejde od začiatku do konca