Tehnični članak

Podvajanje delovnega lista XLSX v Delphi z HotXLS

En delovni list ste pripravili natanko tako, kot mora biti. Glavni pas naslova je združen, širine stolpcev ustrezajo podatkom, zgornji dve vrstici sta zamrznjeni, območje tiskanja in robovi so nastavljeni za čist izvoz na A4, zavihek pa je obarvan, da ga finance hitro najdejo. Zdaj poročilo potrebuje dvanajst takih listov, po enega za vsako regijo, vsi pa morajo začeti iz iste postavitve. Če isti list dvanajstkrat zgradite v kodi, začnejo nastajati drobna odstopanja: regija 7 dobi stolpec, ki je za eno točko ožji, regija 11 izgubi zamrznitev, nihče pa tega ne opazi, dokler PDF ne pristane na direktorjevi mizi. V resnici želite programsko različico Excelovega desnega klika Move or Copy, Create a copy: vzemite dokončan list in naredite iz njega neodvisne dvojnike

XLSX pogon v HotXLS, izvorni knjižnici za Delphi in C++Builder, ki bere in zapisuje Excelove datoteke brez avtomatizacije samega Excela, je že znal premikati liste, brisati liste in kopirati obsege celic med listi. Česar do v2.91.0 ni znal, je bilo kloniranje celotnega delovnega lista z enim klicem. Ta izdaja doda dve vstopni točki: TXLSXWorksheet.CopyFrom, ki kopira stanje na ravni delovnega lista z enega lista na drugega, in TXLSXSheets.Duplicate, ki doda nov list in za vas izvede CopyFrom. Zanimivo ni to, da nekaj kopira. Pomembna je namerna meja med tem, kar se kopira globoko, in tem, kar se ne, ter razlog, zakaj je meja postavljena prav tam

En klic za kloniranje dokončanega lista

Operacija na višji ravni je Duplicate. Podajte ji indeks izvornega lista, ki se začne z 1, in vrne popolnoma nov delovni list, ki zrcali postavitev in podatke izvirnika. Konvencija indeksov se na strani XLSX ujema z Items[], zato je prvi list indeks 1, ne 0; če podate indeks zunaj dovoljenega območja, dobite nil namesto izjeme, kar je enaka pogodba ob napaki, kot jo uporablja preostanek zbirke listov XLSX

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 tem odseku sta vredni počasnejšega branja dve podrobnosti. Prvič, FreezePanes sprejema argumente v vrstnem redu vrstica najprej, FreezePanes(ARow, ACol), zato se ujema z indeksiranjem v Cells[Row, Col]; podvojeni list podeduje natanko enako razdelitev zamrznitve. Drugič, metoda se imenuje Duplicate in ne bolj očitno Copy, kar ni slogovna muha. Copy je standardna rutina v enoti System, ki se stalno uporablja za nize in dinamična polja. Metoda z imenom Copy na razredu bi jo v telesih metod zasenčila in ustvarila natanko tisto dvoumnost pri razreševanju imen, ki vas ugrizne čez pol leta. Duplicate se tej težavi v celoti izogne in se na mestu klica še vedno bere pravilno

Privzeto ime sledi Excelovemu pravilu

Ko pokličete preobremenitev z enim argumentom ali podate prazen niz za ime, se novi list poimenuje po izvornem listu s pripono (2); če ime še ni enolično, se pripona povečuje, dokler ni. Če list Template podvojite enkrat, dobite Template (2); če ga podvojite še enkrat, dobite Template (3), ker je Template (2) že zaseden. To posnema imena, ki jih Excel ustvari s svojim ukazom Create a copy, zato je delovni zvezek, ki ga izdela vaša koda, videti tako, kot bi uporabnik pričakoval pri ročno podvojenem listu. Preverjanje enoličnosti teče proti živi zbirki listov, kar pomeni, da preskoči tudi imena, ki ste jih ustvarili ročno, ne le tistih iz prejšnjih podvajanj

Če ustvarjate en list na regijo ali na mesec, raje uporabite preobremenitev z izrecnim imenom. Predvidljiva shema Region-North, Region-South je pozneje lažja za naslovitev kot niz pripon (2), (3), poleg tega pa ohranja določena imena in formule med listi berljive

Kaj CopyFrom kopira globoko

Pod pokrovom Duplicate doda list in nato pokliče CopyFrom(ASource), ki ga lahko pokličete tudi neposredno, kadar želite klonirati na list, ki ste ga že ustvarili. CopyFrom takoj na začetku zaščiti pred dvema degeneriranima primeroma: kopiranje iz nil ali kopiranje lista samega nase v obeh primerih takoj vrne rezultat in ne naredi ničesar. Vse za tem je samo kopiranje, in to je namenoma široko

Najprej pridejo podatki celic. CopyFrom od izvora zahteva njegov UsedRange, tesen omejitveni okvir zapolnjenih celic in združenih območij, ter ponovno uporabi obstoječi mehanizem CopyRangeTo za prenos vsake vrednosti, formule in indeksa sloga na ravni celice v cilj, začenši pri A1. Nad celicami nato ponovno odigra celotno plast stanja na ravni lista, zaradi katere predloga deluje dokončano:

  • Združena območja, ponovno ustvarjena po koordinatah, tako da pasica pokriva isti pravokotnik
  • Širine stolpcev in višine vrstic ter seznami skritih, zloženih in orisnih ravni, kopirani dobesedno, da se vrstice in stolpci z neprivzetimi nastavitvami poravnajo povsem enako
  • Zamrznjena podokna in stanje pogleda: stopnja povečave, prikaz mreže in ničelnih vrednosti, smer od desne proti levi in vrsta pogleda
  • Stanje zaščite skupaj z dovoljenji za posamezna dejanja, tako da zaklenjena predloga ostane zaklenjena na isti način
  • Celoten blok nastavitev strani: robovi, usmerjenost, velikost papirja, skaliranje in prilagajanje strani, območje tiskanja, naslovi za tisk, glave in noge ter zastavici za tisk mreže in naslovov
  • Območje AutoFilter, barva zavihka in vidnost lista

Rezultat je list, ki se tiska, filtrira in prikazuje enako kot izvor. Ker pa so celice, združitve in seznami dimenzij fizično ponovno ustvarjeni na novem listu in niso le aliasi na isto stanje, je dvojnik povsem neodvisen. Zapišite 999 v celico na kopiji in izvor bo obdržal prvotno vrednost; ta neodvisnost je najpomembnejša lastnost klona, namenjenega vzporednim regionalnim poročilom, in priloženi primer SheetCopy jo izrecno preveri

Kaj ostane plitvo in zakaj

Zdaj pa pošteni del. Grafi, vdelane slike, tabele XLSX, preverjanje veljavnosti podatkov in pravila pogojnega oblikovanja se ne kopirajo. To je dokumentirana in namerna meja, ne spregled, zato je vredno razumeti razlog, da lahko potek načrtujete vnaprej, namesto da vas to preseneti

Vsaka od teh zbirk nosi identiteto in reference, ki ne preživijo naivnega kopiranja polj. Graf kaže na izvorni podatkovni obseg in ima v paketu OOXML lastno relacijo risbe; če objekt klonirate brez ponovnega preslikavanja relacije in referenc serij, dobite graf, ki se izriše nad napačnimi podatki, ali pa paket, ki ga Excel označi kot potreben popravila. Tabela ima ime, ki mora biti enolično znotraj delovnega zvezka, glavno vrstico vezano na določene stolpce in lastno samodejno ustvarjeno relacijo. Pogojna oblikovanja in preverjanja veljavnosti podatkov so pripeta na koordinatne obsege, v primeru validacije pa lahko s formulami kažejo na druge obsege. Pravilno globoko kopiranje česar koli od tega pomeni prepis referenc in ustvarjanje novih identitet, to pa je resnično delo z resničnimi možnostmi napake. Če to opravite napol, tako da kopirate objekt, ne pa tudi njegovih referenc, je to slabše, kot če ga sploh ne kopirate: dobite datoteko, ki se odpre z opozorilom o popravilu in tiho izgubi vsebino. Zato pogon kopira stvari, ki jih lahko čisto kopira, zbirke z referencami pa prepusti klicatelju, ki edini ve, na kaj mora cilj kazati

V praksi to pomeni, da je potek za bogatejšo predlogo takšen: podvojite list, da dobite celice, postavitev in nastavitve tiskanja, nato pa na kopiji znova zgradite graf, tabelo, validacije ali pogojna oblikovanja z istim API-jem, s katerim ste jih prvič ustvarili. Ker jih ponovno ustvarite proti lastnim obsegom dvojnika, so reference pravilne že po zasnovi. Za graf, ki bere A1:C10, dodajte na kopijo nov graf, ki kaže na kopijin A1:C10; če želite aktiven AutoFilter, upoštevajte, da se filtrirni obseg prenese, zato morate znova uporabiti le kriterije po stolpcih. Pravila pogojnega oblikovanja in preverjanja veljavnosti podatkov ponovno dodate z istimi klici, opisanimi v članku o združenih celicah in postavitvi predlog poročil, ki obravnava tabelo združitev in model obsega, ki ga kopija podeduje

Kje se podvajanje prilega v poročevalni cevovod

Podvajanje delovnih listov je naravni spremljevalec generiranja, ki temelji na označevalnikih mest. Pristop, zasidran na žetonih, v vodniku za generiranje poročil iz predlog v Delphi rešuje problem pisanja podatkov v postavitev, ki jo urejajo drugi ljudje; podvajanje pa rešuje problem, ko isto postavitev potrebujete večkrat v enem delovnem zvezku. Skupaj je vzorec čist: ohranite en neomadeževan list Template z njegovimi žetoni, združitvami in nastavitvami tiskanja, nato pa za vsako regijo ali obdobje pokličite Duplicate, zapolnite žetone klona s tem rezom podatkov in nadaljujte. Neokrnjena predloga se nikoli ne spremeni, zato ostane zanesljiv vir za naslednji klon, vsak izhodni list pa začne iz bitno enake postavitve

Ena opomba o zaporedju prihrani celo vrsto zmede. List podvojite preden vanj nalijete podatke, ne potem. Predloga naj vsebuje strukturo in oblikovanje, ne lanskih številk, in kloniranje praznega oblikovanega lista pomeni, da vsaka kopija začne čisto. Če podvojite list, ki že vsebuje podatke, ti podatki pridejo zraven, ker CopyFrom zvesto kopira uporabljeni obseg; občasno je to prav tisto, kar želite, za poročilo z razvejitvijo na več listov pa običajno ne

Hitra navada preverjanja

Ker je ločnica med globokim in plitvim kopiranjem nevidna, dokler je ne začnete iskati, v opravilo raje vgradite petvrstični preizkus, namesto da preprosto zaupate, da se je vse preneslo. Po podvajanju preberite nazaj strukturne signale, ki jih mora klon podedovati, in preverite, da se ujemajo z izvorom

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.

Število združitev, širina stolpca, zamrznjena vrstica in zastavica barve zavihka vam povedo, da je plast, ki se dejansko kopira, res prišla skozi. Ločeno pa pri vsakem listu, ki je imel graf, tabelo, validacije ali pogojna oblikovanja, te elemente obravnavajte kot seznam za ponovno izgradnjo na kopiji: njihova odsotnost je pričakovana, popravek pa je nekaj klicev, ne prijava hrošča. Ta miselni model, globoko tam, kjer je varno, in plitvo tam, kjer bi reference razpadle, je celotna zgodba o tem, kako to funkcijo dobro uporabljati

Podvajanje delovnih listov in kopiranje stanja lista z CopyFrom, opisano tukaj, sta na voljo v v2.91.0 izvorne komponente HotXLS za preglednice v Delphi, skupaj z izvedljivim primerom SheetCopy, ki od začetka do konca preizkusi cikel kloniranja in spreminjanja