Du har bygget ét ark helt rigtigt. Overskriftsbåndet er flettet, kolonnebredderne passer til dataene, de to øverste rækker er frosset, printområdet og margenerne er sat til en ren A4-udskrift, og fanen har farve, så økonomiafdelingen kan finde den. Nu skal rapporten bruge tolv af disse ark, ét pr. region, alle med samme udgangspunkt i layoutet. Genopbygger du arket i kode tolv gange, er det sådan, subtil afvigelse sniger sig ind: region 7 får en kolonne, der er en anelse smallere, region 11 mister frysningen, og ingen opdager det, før PDF'en lander på en leders skrivebord. Det, du egentlig vil have, er den programmatiske udgave af Excels højreklik, Flyt eller kopiér, Opret en kopi: tag det færdige ark og stemp uafhængige duplikater ud
XLSX-motoren i HotXLS, et native Delphi- og C++Builder-bibliotek der læser og skriver Excel-filer uden at automatisere selve Excel, kunne allerede flytte ark, slette ark og kopiere celleområder mellem ark. Det, den ikke kunne før v2.91.0, var at klone et helt regneark med ét kald. Den udgivelse tilføjer to indgangspunkter: TXLSXWorksheet.CopyFrom, som kopierer ark-niveau tilstand fra ét regneark til et andet, og TXLSXSheets.Duplicate, som tilføjer et nyt ark og kører CopyFrom for dig. Det spændende er ikke, at den kan kopiere ting. Det er den bevidste grænse, der er trukket mellem det, der dybdekopieres, og det, der ikke gør, og hvorfor grænsen ligger lige dér
Ét kald til at klone et færdigt ark
Den overordnede operation er Duplicate. Angiv kildearkets 1-baserede indeks, og den returnerer et splinternyt regneark, der spejler originalens layout og data. Indekskonventionen følger Items[] på XLSX-siden, så ark ét har indeks 1, ikke 0; angiver du et indeks uden for grænserne, får du nil i stedet for en undtagelse, samme fejlkontrakt som resten af XLSX-arksamlingen bruger
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); // frys øverste række + første kolonne
Template.TabColorIsAuto := False;
Template.TabColor := $FF1F4E79;
// Klon med et eksplicit navn...
Copy := Book.Sheets.Duplicate(1, 'Region-North');
// ...eller lad den vælge Excel-stilens standardnavn.
Copy := Book.Sheets.Duplicate(1); // -> "Template (2)"
Book.SaveAs('regions.xlsx');
finally
Book.Free;
end;
end;
Der er to ting i det udsnit, det er værd at stoppe op ved. For det første tager FreezePanes sine argumenter i rækkefølgen række-først, FreezePanes(ARow, ACol), så det passer med indekseringen i Cells[Row, Col]; duplikatet arver præcis den samme frysningsopdeling. For det andet hedder metoden Duplicate og ikke det mere oplagte Copy, og det er ikke en stilpræference. Copy er en standardrutine i enheden System, som bruges konstant til strenge og dynamiske arrays. En metode kaldet Copy på en klasse ville skygge for den inde i metodekroppe og skabe præcis den slags opløsningstvetydighed, der bider dig seks måneder senere. Duplicate undgår hele problemet og læses korrekt ved kaldestedet
Standardnavnet følger Excels egen regel
Når du kalder den enkeltargument-overload, eller angiver en tom navnestreng, får det nye ark navn efter kilden med et (2)-suffiks, og suffikset tæller op, indtil navnet er unikt. Duplikerer du Template-arket én gang, får du Template (2); duplikerer du det igen, får du Template (3), fordi Template (2) allerede er optaget. Det spejler de navne, Excel selv genererer fra sin kommando Opret en kopi, så en arbejdsbog, din kode producerer, ser ud, som en bruger ville forvente af en manuelt duplikeret én. Unikhedstjekket kører mod den aktive arksamling, hvilket betyder, at den også springer uden om navne, du har oprettet manuelt, ikke kun dem fra tidligere dupliceringer
Genererer du ét ark pr. region eller pr. måned, bør du hellere bruge overloaden med eksplicit navn. Et forudsigeligt Region-North, Region-South-skema er lettere at adressere senere end en række (2), (3)-suffikser, og det holder dine definerede navne og krydsark-formler læsbare
Hvad CopyFrom kopierer dybt
Under motorhjelmen tilføjer Duplicate arket og kalder derefter CopyFrom(ASource), som du også kan kalde direkte, når du vil klone ind på et ark, du allerede har oprettet. CopyFrom tjekker for de to degenererede tilfælde med det samme: kopiering fra nil eller kopiering af et ark ind på sig selv returnerer begge med det samme og gør ingenting. Alt derefter er selve kopieringen, og den er bevidst bred
Celledataene kommer først. CopyFrom beder kilden om dens UsedRange, den tætte afgrænsningsboks for udfyldte celler og flettede områder, og genbruger den eksisterende CopyRangeTo-maskine til at overføre hver værdi, formel og pr.-celle stilindeks til målet med start ved A1. Oven på cellerne genafspiller den hele laget af ark-niveau tilstand, der får en skabelon til at se færdig ud:
- Flettede områder, genskabt efter koordinat, så banneret dækker det samme rektangel
- Kolonnebredder og rækkehøjder, samt listerne over skjulte, sammenklappede og dispositionsniveauer, kopieret ordret, så rækker og kolonner, der afviger fra standard, passer nøjagtigt
- Fastfrosne ruder og visningstilstanden: zoomniveau, visning af gitterlinjer og nulværdier, retning fra højre mod venstre, og visningstypen
- Beskyttelsestilstand med dens pr.-handling tilladelsesindstillinger, så en låst skabelon forbliver låst på samme måde
- Hele siden-opsætning-blokken: margener, retning, papirstørrelse, skalering og tilpas-til-side, printområde, printtitler, sidehoveder og sidefødder, samt flagene for udskrivning af gitterlinjer og overskrifter
- AutoFilter-området, fanens farve og arkets synlighed
Resultatet er et ark, der printer, filtrerer og fremtræder identisk med kilden. Og fordi cellerne, fletningerne og dimensionslisterne fysisk genskabes på det nye ark i stedet for at blive aliaseret, er duplikatet fuldstændig uafhængigt. Skriv 999 ind i en celle på kopien, og kilden bevarer sin oprindelige værdi; den uafhængighed er den vigtigste enkeltstående egenskab ved et klon beregnet til parallelle regionale rapporter, og den medfølgende SheetCopy-demo påviser det eksplicit
Hvad det lader være overfladisk, og hvorfor
Nu til den ærlige del. Diagrammer, indlejrede billeder, XLSX-tabeller, datavalideringer og regler for betinget formatering bliver ikke kopieret. Det er en dokumenteret, bevidst grænse, ikke en forglemmelse, og det er værd at forstå ræsonnementet, så du kan planlægge efter det i stedet for at blive overrasket over det
Hver af disse samlinger bærer identitet og referencer, der ikke overlever en naiv feltkopiering. Et diagram peger på et kildedataområde og ejer en tegnerelation i OOXML-pakken; at klone objektet uden at omlægge relationen og seriereferencerne giver et diagram, der tegnes mod de forkerte data, eller en pakke, som Excel markerer som havende brug for reparation. En tabel har et navn, der skal være unikt inden for arbejdsbogen, en overskriftsrække bundet til bestemte kolonner, og sin egen automatisk genererede relation. Betingede formater og datavalideringer knytter sig til koordinatområder og kan i valideringens tilfælde referere til andre områder via formel. At dybdekopiere nogen af disse korrekt betyder at omskrive referencer og præge nye identiteter, hvilket er reelt arbejde med reelle fejltilstande. At gøre det halvt, ved at kopiere objektet men ikke dets referencer, er værre end slet ikke at kopiere: det giver en fil, der åbner med en reparationsprompt og stiltiende dropper indhold. Så motoren kopierer de ting, den kan kopiere rent, og overlader de referencebærende samlinger til den kaldende kode, som ved, hvad målet skal pege på
I praksis betyder det, at arbejdsgangen for en rigere skabelon er: duplikér arket for at få cellerne, layoutet og printopsætningen, og genopbyg derefter diagrammet, tabellen, valideringerne eller de betingede formater på kopien med samme API, du brugte til at oprette dem første gang. Fordi du genskaber dem mod duplikatets egne områder, kommer referencerne ud korrekt i kraft af konstruktionen. For et diagram, der læser A1:C10, tilføjer du et nyt diagram på kopien, der peger på kopiens A1:C10; for et AutoFilter, du vil have levende, bemærk, at filterets område faktisk overføres, så du kun skal genanvende kolonnekriterierne. Reglerne for betinget formatering og datavalidering skal du genskabe gennem de samme kald, som beskrives i artiklen om flettede celler og skabelonlayout til rapporter, som gennemgår fletningstabellen og områdemodellen, kopien arver
Hvor duplikering passer ind i en rapporteringspipeline
Arkduplikering er den naturlige makker til pladsholder-drevet generering. Den token-forankrede tilgang i guiden til skabelondrevet rapportgenerering i Delphi løser problemet med at skrive data ind i et layout, andre redigerer; duplikering løser problemet med at have brug for det layout mange gange i én arbejdsbog. Kombinerer du dem, bliver mønsteret rent: behold ét urørt Template-ark med dets tokens, fletninger og printopsætning, og kald derefter Duplicate for hver region eller periode, udfyld klonens tokens med den udsnit af data, og gå videre. Det urørte skabelonark bliver aldrig ændret, så det forbliver en pålidelig kilde til den næste klon, og hvert outputark starter fra et byte-for-byte identisk layout
Én bemærkning om rækkefølgen sparer dig for en hel klasse af forvirring. Duplikér arket før, du hælder data i det, ikke efter. En skabelon bør indeholde struktur og formatering, ikke sidste kvartals tal, og at klone et tomt, formateret ark betyder, at hvert duplikat starter rent. Duplikerer du et ark, der allerede bærer data, følger de data med, fordi CopyFrom kopierer det anvendte område trofast; det er lejlighedsvis, hvad du vil have, men for en fan-out-rapport er det som regel ikke
En hurtig verifikationsvane
Fordi opdelingen mellem dybdekopi og overfladekopi er usynlig, indtil du leder efter den, bør du bygge et fem-linjers tjek ind i jobbet i stedet for at stole på, at alt kom med. Efter dupliceringen læser du de strukturelle signaler tilbage, som klonen forventes at have arvet, og bekræfter, at de matcher kilden
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)]));
// Bevis uafhængighed: ændr kopien, bekræft at kilden er urørt.
Copy.Cells[2, 2].Value := 999;
// Template.Cells[2, 2].Value er stadig, hvad den var.
Fletningsantallet, en kolonnebredde, frysningsrækken og fane-farve-flaget fortæller dig, at det lag, der faktisk kopieres, kom med. Separat skal du i ethvert ark, der bar et diagram, en tabel, valideringer eller betingede formater, behandle dem som en genopbygningsliste på kopien: deres fravær er tilsigtet, og løsningen er nogle få kald, ikke en fejlrapport. Den mentale model, dyb hvor det er sikkert og overfladisk hvor referencer ville gå i stykker, er hele historien om, hvordan man bruger denne funktion godt
Arkduplikering og den CopyFrom-ark-tilstandskopiering, der er beskrevet her, følger med i v2.91.0 af den native HotXLS Delphi regnearkskomponent, sammen med et kørbart SheetCopy-eksempel, der afprøver klon-og-ændr-cyklussen fra ende til anden