Műszaki cikk

HotXLS: Lapszintű védelem, oldalbeállítás és nyomtatás Delphi-ben

Három munkalap-beállításcsoportnak semmi köze a cellaértékekhez, és minden köze ahhoz, hogyan viselkedik a fájl, miután elhagyta a kódját. A munkalapvédelem dönti el, mely cellákat szerkesztheti a felhasználó, miután átadta a workbookot. Az oldalbeállítás rögzíti a tájolást, a papírméretet és a margókat. A nyomtatási beállítások – az ismétlődő címsorok, a méretezés és a kézi oldaltörések – szabályozzák, hogyan kerül papírra egy tetszőleges hosszúságú rács. Egyik sem látszik, amikor egy megjelenítőben végigfutja az adatokat, és mind a három csendben tör el az éles életben, ha rosszul van beállítva. A HotXLS, a natív Delphi és C++Builder táblázatkezelő könyvtár, a teljes felületet elérhetővé teszi .xls és .xlsx formátumhoz, ami azt is jelenti, hogy minden ellentmondásosnak tűnő Excel-szabályt reprodukál, amely ebbe a felületbe bele van sütve

E szabályok közül az első szinte mindenkit megtréfál, amikor először véd le egy generált munkalapot. Meghívja a Protect metódust, és hirtelen senki nem tud egyetlen cellába sem gépelni, beleértve azokat a beviteli oszlopokat is, amelyek köré az egész workbookot építette. A kódja hozzájuk sem nyúlt, és pontosan ezért történik ez

Minden cella zároltan születik

Az ECMA-376 a locked tulajdonságot a cella formázási rekordjának részeként definiálja, nem magának a védelemnek a tulajdonságaként, és az alapértéke igaz. A munkalapvédelem pusztán az a kapcsoló, amely kikényszeríthetővé teszi a jelzőt. A teljes rács tehát a létrejötte pillanatától visel egy alvó zárolási jelzőt, és a Protect hívás egyszerre aktiválja mindet. A megoldás a sorrend tudatos megválasztása: építse fel az elrendezést, kifejezetten oldja fel azokat a tartományokat, amelyeket a felhasználóknak szerkeszteniük kell, és a védelmet hagyja utoljára

Diagram a HotXLS védelmi sorrendről Delphi-ben: minden cella locked trueval születik, a bemeneti tartományok először SetLockeddel oldódnak fel, és az utoljára hívott Sheet.Protect hagyja szerkeszthetően a feloldott cellákat
A cellák alapértelmezetten zárolva érkeznek, ezért előbb oldja fel a bemeneti tartományokat, és hívja a Protectet utoljára, hogy szerkeszthetők maradjanak
Book := TXLSXWorkbook.Create;
try
  Sheet := Book.Sheets.Add('Timesheet');
  // ... a fejlécsor, a névoszlop és a díjszabási képletek ide íródnak ...
  Sheet.Range['B2:B50'].SetLocked(False);         // ide írja a személyzet az órákat
  Sheet.Range['F2:F50'].SetFormulaHidden(True);   // a díjszámítás maradjon rejtve
  Sheet.Protect('review-2026');                   // a zárolási jelzők mostantól harapnak
  Book.SaveAs('timesheet.xlsx');
finally
  Book.Free;
end;

A SetFormulaHidden külön dolgot csinál, amelyet könnyű elnézni: amíg a védelem aktív, a cella továbbra is mutatja a számított értékét, de a szerkesztőléc semmit nem mutat. Ez akkor számít, amikor egy képlet olyan díjszabást, árrést vagy pontozási súlyt tartalmaz, amelyet nem szívesen adna át minden címzettnek, aki rákattint egy végösszegre. Az XLS-felületen ugyanezt a szándékot tartományonként az IXLSRange.Locked és a FormulaHidden fejezi ki. Az ottani munkalap tizenöt Allow* jelzőt is visel (AllowSort, AllowAutoFilter, AllowFormatCells és a többi), így egy védett munkalap továbbra is rendezhető és szűrhető marad, nem fagy lezárt tárlati darabbá

Mit véd valójában a védelmi jelszó

Mindkét formátum 4 hexadecimális jegyű, örökölt kivonatként tárolja a munkalap és a workbook védelmi jelszavát. Tizenhat bit azt jelenti, hogy bármely adott jelszóval számtalan sztring ütközik, az eltávolító eszközök pedig egy keresésre vannak. A védelmet a véletlen szerkesztések elleni biztonsági övként kezelje, ne hozzáférés-vezérlésként. Ez a helyes eszköz arra, hogy a bírálók ne gépeljenek bele a képletoszlopba, és a rossz eszköz mindenre, ami a bizalmas szót is tartalmazza

Egy szinttel feljebb a ProtectWorkbook az XLSX-felületen a workbook szerkezetét zárolja, ami megakadályozza a munkalapok hozzáadását, átnevezését, törlését és átrendezését. Állítsa be, valahányszor maga a munkalaplista is szerződés egy olyan alsóbb elemzővel, amely név vagy pozíció szerint indexeli a lapokat. Egy átnevezett munkalap ugyanolyan biztosan töri el az importálást a másik oldalon, mint egy törölt oszlop. Az XLS-felület a rétegzést a workbook szintű TXLSWorkbook.Protect hívással és a munkalaponkénti Protect hívásokkal tükrözi, ezenfelül ad egy isProtected tulajdonságot annak a kódnak, amelynek meg kell vizsgálnia egy örökölt fájlt, mielőtt bármit módosítana

Amikor a követelmény valódi bizalmasság, a mechanizmus teljesen megváltozik. A SaveAsEncrypted AES-titkosított csomagot állít elő az ECMA-376 Standard Encryption séma szerint – ezt mélységében az AES-védett XLSX-kimenetről szóló útmutató tárgyalja –, a régi XLS-felület pedig RC4-titkosított .xls fájlokat ír és olvas az EncryptionPassword tulajdonságon és az Open jelszavas túlterhelésén keresztül. A különbség nem elméleti. A védett munkalap tiszta szövegként utazik, tehát bármelyik zip-eszköz kiolvashatja a cellaértékeit, míg a titkosított csomag jelszó nélkül olvashatatlan. Az az auditsor, amely szerint „a bérszámfejtési fájlt védeni kell”, majdnem mindig titkosítást jelent, bármilyen szóhasználattal él is

Diagram: HotXLS munkalapvédelem, amely 16 bites örökölt hasht tárol, és nyílt szövegben hagyja a cellaértékeket, olvashatóan bármely zip eszközzel, szemben a SaveAsEncrypted AES kimenettel, amely jelszó nélkül olvashatatlan marad
A munkalapvédelem biztonsági öv a véletlen szerkesztések ellen, miközben a nyílt szöveges értékek olvashatók maradnak, és csak az AES-titkosítás rejti el a tartalmat

Az oldalbeállítás a dokumentumszerződés része

A nyomtatási viselkedés a képernyőn láthatatlan, és részben ezért kerül ki olyan gyakran hibásan. Abban a pillanatban, hogy egy ügyfél kinyomtatja a workbookot, vagy PDF-be exportálja egy auditornak, a margók, a méretezés és az ismétlődő címsorok olyan funkcionális követelménnyé válnak, amelyet senki nem tesztelt. Az XLSX-felületen ezek a beállítások közvetlenül a munkalapon lógnak:

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';     // csupasz hivatkozás: munkalapnév nélkül
Sheet.PrintTitleRows := '$1:$1';     // a fejlécsor minden oldalon ismétlődik
Sheet.FitToWidth := 1;
Sheet.FitToHeight := 0;              // lefelé nő, ahogy az adat nő
Sheet.PrintGridlines := False;

Ezek közül két sor csapdát rejt. A fejléc- és láblécsztringek az Excel formázókódjait használják: a &P az aktuális oldal, a &N az összes oldal száma, a &L, a &C és a &R pedig a három szakaszt címzi meg kifejezetten. A másik csapda a PrintArea, amely szándékosan csupasz cellahivatkozást vár. A HotXLS minősítés nélkül tárolja, és fájlíráskor teszi elé a munkalap nevét, tehát ha maga adja át a 'Timesheet!$A$1:$F$60' alakot, kétszeresen minősített, hibás hivatkozást állít elő. Ugyanez az óvatosság érvényes egy réteggel lejjebb: a nyomtatási területek és a nyomtatási címsorok a beépített _xlnm.Print_Area és _xlnm.Print_Titles definiált nevekként őrződnek meg, ezért soha ne vegyen fel kézzel _xlnm.* bejegyzéseket a DefinedNames gyűjteményen keresztül, különben a két mechanizmus ugyanazon a helyen fog veszekedni

Méretezés, amely kibírja az éles adatmennyiséget

A FitToWidth := 1 és a FitToHeight := 0 párosa így olvasandó: „az oszlopok mindig férjenek el egy oldal szélességében, lefelé pedig annyi oldal legyen, amennyit az adat kíván” – és ez a helyes alapértelmezés minden olyan jelentéshez, amelynek változik a sorszáma. A csapda az, ha egy rögzített százalékot vagy egy oldalhoz igazítási párost harminc soros tesztfájlon hangol be: adjon ugyanezeknek a beállításoknak hatszáz éles sort, és a kimenet vagy tucatnyi levágott oldalba robban szét, vagy az olvashatóság alá zsugorodik. A szélességet méretezze, a hosszt hagyja nőni, és a PrintTitleRows beállítással ismételtesse a fejlécsort, hogy a tizenhetedik oldal önmagában is olvasható legyen

Diagram a HotXLS nyomtatási skálázásról Delphi-ben: FitToWidth 1re állítva, így minden oldal egy lap széles marad, FitToHeight 0ra állítva, így az oldalak lefelé nőnek, PrintTitleRows ismétli a fejlécsávot, oldaltörések pedig újragenerálódnak ClearAllPageBreaks után
A FitToWidth 1 és FitToHeight 0 minden oldalt egy lap szélességűen tart, miközben az ismétlődő címsorok és az újragenerált törések megőrzik az olvashatóságot

A kézi törésekre ugyanaz az újragenerálási fegyelem vonatkozik, mint egy generált workbook minden más elemére. Az AddRowBreak(BeforeRow) új oldalt kezd egy szakaszhatár előtt, de amikor a generátor újra lefut, és a sorok elmozdulnak, egy elavult törés a táblázat közepén landol. Előbb hívja meg a ClearAllPageBreaks metódust, majd a generátor saját sorszámlálóiból számított töréseket vegye fel újra, ahelyett hogy régi pozíciókat foltozgatna. Az XLS-felületen a megfelelő vezérlők a Sheet.PageSetup alatt élnek (tájolás, papírméret, margók, fejléc- és láblécsztringek, oldalhoz igazítás), a nyomtatási címsorokat pedig a RepeatRows és a RepeatColumns fedi le

Ellenőrizze az eredményt, mielőtt az ügyfél teszi

A védelmi és a nyomtatási hibák egy tulajdonságon osztoznak: kézzel triviálisan ellenőrizhetők, és szinte soha nem ellenőrzik őket. Nyissa meg a generált fájlt Excelben, és szánjon rá kilencven másodpercet. Gépeljen egy beviteli cellába, és győződjön meg róla, hogy elfogadja a leütést; gépeljen egy zárolt cellába, és győződjön meg róla, hogy megjelenik a védelmi üzenet; ellenőrizze, hogy egy rejtett képletnél a szerkesztőléc üresen marad. Utána futtasson nyomtatási képet éles méretű adathalmazon, ne harminc soros mintán, és olvassa le az oldalszámot, az ismétlődő címsort és a lábléc számozását. Az előnézet az a lépés, amely megtermeli az árát, mert a nyomtatási geometria olyan beállításoktól függ, amelyeknek nincs képernyős megjelenítése, és fizikai nyomtató híján ez az egyetlen hely, ahol egy méretezési hiba egyáltalán láthatóvá válik

Egy utolsó beállítás kerekíti le a bírálatot. A FreezePane(ACol, ARow) a fejlécblokkot látótérben tartja, miközben a bíráló görget. Ez képernyős, nem nyomtatási viselkedés, de a bíráló az egész szállítmányt egyszerre ítéli meg. Az a workbook pedig, amely tervező által karbantartott elrendezésként indul, mindezt jórészt ingyen kapja: a sablonalapú jelentésgenerálási munkamenet az oldalbeállítást a sablonban tartja, ahol egy ember valódi nyomtatóhoz hangolta, a kódra pedig csak az adatok feltöltését és a védelem ismételt alkalmazását hagyja, miután az elrendezés letisztult

A HotXLS natív Object Pascal táblázatkezelő könyvtár Delphihez és C++Builderhez; a teljes védelmi és oldalbeállítási API-referencia a HotXLS Delphi Component termékoldalon található