Technical Article

HotXLS: Ochrana hárkov, nastavenie stránky a tlač v Delphi

Tri skupiny nastavení pracovného hárka nemajú nič spoločné s hodnotami buniek, no ovplyvňujú všetko ohľadom správania súboru po opustení vášho kódu. Ochrana hárka určuje, ktoré bunky môže používateľ po odovzdaní zošita upravovať. Nastavenie stránky definuje orientáciu, veľkosť papiera a okraje. Nastavenia tlače (opakujúce sa riadky s nadpismi, mierka a manuálne zlomy strán) určujú, ako sa tabuľka ľubovoľnej dĺžky vykreslí na papieri. Žiadna z týchto troch skupín sa neprejaví pri vizuálnej kontrole dát v prehliadači, no všetky tri ticho zlyhávajú v praxi, ak sú nastavené nesprávne. HotXLS, natívna knižnica pre tabuľky v Delphi a C++Builderi, sprístupňuje kompletné rozhranie pre formáty .xls a .xlsx, čo znamená, že reprodukuje aj všetky protichodné pravidlá Excelu zakomponované do tohto rozhrania.

Prvé z týchto pravidiel potrápi takmer každého, kto prvýkrát chráni vygenerovaný hárok. Zavoláte metódu Protect a zrazu nikto nemôže písať do žiadnej bunky, vrátane vstupných stĺpcov, okolo ktorých ste zošit postavili. Nič vo vašom kóde sa týchto stĺpcov nedotklo, a to je presne ten dôvod, prečo k tomu dochádza.

Každá bunka sa rodí uzamknutá

ECMA-376 definuje vlastnosť locked (uzamknutá) ako súčasť záznamu o formátovaní bunky, nie ako vlastnosť samotnej ochrany, a jej predvolená hodnota je true. Ochrana hárka je len prepínač, ktorý robí tento príznak vynútiteľným. Celá mriežka teda nesie príznak uzamknutia od momentu svojho vzniku (v neaktívnom stave) a volanie Protect aktivuje všetky tieto príznaky naraz. Riešením je stanoviť poradie krokov zámerne: vytvorte rozloženie, explicitne odomknite rozsahy, ktoré musia používatelia upravovať, a ochranu aplikujte ako posledný krok.

Book := TXLSXWorkbook.Create;
try
  Sheet := Book.Sheets.Add('Timesheet');
  // ... header row, name column, and rate formulas written here ...
  Sheet.Range['B2:B50'].SetLocked(False);         // staff type hours here
  Sheet.Range['F2:F50'].SetFormulaHidden(True);   // keep the rate math private
  Sheet.Protect('review-2026');                   // now the lock flags bite
  Book.SaveAs('timesheet.xlsx');
finally
  Book.Free;
end;

Metóda SetFormulaHidden robí niečo samostatné a ľahko prehliadnuteľné: kým je ochrana aktívna, bunka stále zobrazuje svoju vypočítanú hodnotu, no riadok vzorcov (formula bar) nezobrazuje nič. To je dôležité, keď vzorec obsahuje zúčtovacie sadzby, marže alebo váhy hodnotenia, ktoré by ste radšej neukazovali každému príjemcovi, ktorý klikne na celkový súčet. Na strane rozhrania XLS se rovnaký zámer vyjadruje pre konkrétny rozsah cez vlastnosti IXLSRange.Locked a FormulaHidden. Hárok tam tiež obsahuje pätnásť príznakov Allow* (ako AllowSort, AllowAutoFilter, AllowFormatCells a ďalšie), takže chránený hárok je možné stále triediť a filtrovať namiesto toho, aby bol úplne zablokovaný.

Čo heslo na ochranu hárka v skutočnosti chráni

Oba formáty ukladajú heslo na ochranu hárka a zošita ako 4-miestny hexadecimálny starší hash. Šestnásť bitov znamená, že s akýmkoľvek daným heslom koliduje množstvo iných reťazcov a nástroje na odstránenie hesla sú vzdialené jedno vyhľadávanie v prehliadači. Pristupujte k ochrane ako k bezpečnostnému pásu proti náhodným úpravám, nie ako k riadeniu prístupu k dátam. Je to správny nástroj na zabránenie prepísania stĺpca so vzorcami používateľmi, no nesprávny nástroj na čokoľvek, čo nesie označenie dôverné.

O úroveň vyššie metóda ProtectWorkbook v rozhraní XLSX uzamyká štruktúru zošita, čo zabraňuje pridávaniu, premenovávaniu, odstraňovaniu alebo presúvaniu hárkov. Nastavte ju vždy, keď je samotný zoznam hárkov zmluvou s nadväzujúcim spracovaním, ktoré indexuje hárky podľa názvu alebo pozície. Premenovaný hárok naruší import na druhej strane rovnako spoľahlivo ako vymazaný stĺpec. Rozhranie XLS kopíruje toto vrstvenie pomocou vlastnosti TXLSWorkbook.Protect na úrovni zošita a volaní Protect pre jednotlivé hárky, a tiež poskytuje vlastnosť isProtected pre kód, ktorý potrebuje skontrolovať importovaný súbor pred jeho úpravou.

Ak je požiadavkou skutočná dôvernosť, mechanizmus sa úplne mení. Metóda SaveAsEncrypted vytvára balík šifrovaný algoritmom AES pod schémou štandardného šifrovania ECMA-376, ktorej sa podrobne venuje sprievodca šifrovaným výstupom XLSX, a staršie rozhranie XLS zapisuje a číta súbory .xls šifrované prúdom RC4 cez vlastnosť EncryptionPassword a preťaženie metódy Open s heslom. Rozdiel nie je akademický. Chránený hárok sa prenáša ako nešifrovaný text, takže akýkoľvek zip archívny nástroj dokáže prečítať hodnoty jeho buniek, zatiaľ čo šifrovaný balík je bez hesla nečitateľný. Požiadavka typu „súbor s mzdami musí byť chránený“ takmer vždy znamená šifrovanie, bez ohľadu na použitú terminológiu.

Nastavenie stránky je súčasťou štruktúry dokumentu

Správanie pri tlači je na obrazovke neviditeľné, a preto sa tak často stáva, že nefunguje správne. V momente, keď zákazník vytlačí zošit alebo ho exportuje do formátu PDF pre audítora, okraje, mierka a opakujúce sa nadpisy sa stávajú funkčnými požiadavkami, ktoré nikto neotestoval. V rozhraní XLSX tieto nastavenia patria priamo pod hárok:

Sheet.PageLandscape := True;
Sheet.PaperSize := xlsxPaperA4;
Sheet.SetPageMargins(0.5, 0.5, 0.75, 0.75, 0.3, 0.3);
Sheet.CenterHeader := 'Monthly Timesheet';
Sheet.RightFooter := 'Page &P of &N';
Sheet.PrintArea := '$A$1:$F$60';     // bare reference: no sheet name here
Sheet.PrintTitleRows := '$1:$1';     // header row repeats on every page
Sheet.FitToWidth := 1;
Sheet.FitToHeight := 0;              // grow downward as the data grows
Sheet.PrintGridlines := False;

Dva z týchto riadkov skrývajú pasce. Reťazce hlavičky a pätky používajú formátovacie kódy Excelu: &P pre aktuálnu stránku, &N pre celkový počet, pričom &L, &C a &R explicitne adresujú tri sekcie. Druhou pascou je PrintArea, ktorá zámerne prijíma čistý odkaz na bunku. HotXLS ho ukladá nekvalifikovaný a predponu s názvom hárka pridáva až pri zápise súboru, takže ručné odovzdanie 'Timesheet!$A$1:$F$60' vytvorí duplicitne kvalifikovaný, neplatný odkaz. Rovnaké upozornenie platí aj o úroveň nižšie: oblasti tlače a tlačové nadpisy sa ukladajú ako vstavané definované názvy _xlnm.Print_Area a _xlnm.Print_Titles, preto nikdy nepridávajte záznamy _xlnm.* cez DefinedNames ručne, inak budú oba mechanizmy bojovať o rovnaké miesto.

Mierka, ktorá zvládne produkčné objemy dát

Kombinácia FitToWidth := 1 a FitToHeight := 0 sa interpretuje ako „vždy prispôsobiť stĺpce na šírku jednej stránky a na výšku použiť toľko stránok, koľko dáta vyžadujú“. Ide o správne predvolené nastavenie pre akýkoľvek report s premenlivým počtom riadkov. Pascou je ladenie pevného percenta alebo páru hodnôt prispôsobenia na stránku voči testovaciemu súboru s tridsiatimi riadkami: odovzdajte rovnaké nastavenia šiestim stovkám produkčných riadkov a výstup sa buď rozloží na desiatky orezaných stránok, alebo sa zmenší pod úroveň čitateľnosti. Prispôsobte šírku, nechajte výšku rásť a zopakujte riadok s hlavičkou cez PrintTitleRows, aby bola aj sedemnásta strana čitateľná sama o sebe.

Manuálne zlomy strán sa riadia rovnakou disciplínou regenerácie ako všetko ostatné v generovanom zošite. Metóda AddRowBreak(BeforeRow) začína novú stránku pred hranicou sekcie, no keď sa generátor spustí znova a riadky sa posunú, starý zlom skončí uprostred tabuľky. Najprv zavolajte ClearAllPageBreaks a potom znova pridajte zlomy vypočítané z počítadiel riadkov generátora, namiesto opravovania starých pozícií. V rozhraní XLS sa ekvivalentné nastavenia nachádzajú na vlastnosti Sheet.PageSetup (orientácia, veľkosť papiera, okraje, hlavičky a pätky, prispôsobenie stránkam), pričom opakujúce sa riadky a stĺpce pokrývajú metódy RepeatRows a RepeatColumns.

Kontrola výsledku pred zákazníkom

Chyby ochrany a tlače majú jednu spoločnú vlastnosť: dajú sa jednoducho overiť ručne, no takmer nikdy sa neoverujú. Otvorte vygenerovaný súbor v Exceli a venujte mu deväťdesiat sekúnd. Skúste písať do vstupnej bunky a overte, že prijíma stlačenia klávesov; skúste písať do zamknutej bunky a overte, že sa zobrazí upozornenie ochrany; skontrolujte, či skrytý vzorec ponecháva riadok vzorcov prázdny. Potom spustite Ukážku pred tlačou (Print Preview) nad dátami s produkčnou veľkosťou, nie nad vzorkou s tridsiatimi riadkami, a skontrolujte počet strán, opakujúci sa riadok hlavičky a číslovanie strán v pätke. Ukážka pred tlačou je krok, ktorý sa oplatí, pretože geometria tlače závisí od nastavení bez vizuálneho zobrazenia na obrazovke a okrem fyzickej tlačiarne je to jediné miesto, kde sa chyba v mierke prejaví.

Posledné nastavenie dopĺňa celkovú kontrolu. Metóda FreezePane(ACol, ARow) ukotví hlavičky pri skrolovaní. Ide o správanie na obrazovke, nie pri tlači, no príjemca hodnotí celý odovzdaný dokument naraz. A zošit, ktorý začína svoj život ako šablóna udržiavaná dizajnérom, získava väčšinu týchto vlastností zadarmo: proces generovania reportov zo šablón ponecháva nastavenie stránky v šablóne, kde ho človek vyladil voči skutočnej tlačiarni, a necháva kód iba na naplnenie dát a opätovné zapnutie ochrany po usadení rozloženia.

HotXLS je natívna knižnica pre tabuľky v Object Pascale pre Delphi a C++Builder; kompletná referenčná príručka k rozhraniu API pre ochranu a nastavenie stránky je k dispozícii na produktovej stránke komponentu HotXLS.