Trei grupuri de setări ale foii de calcul nu au nicio legătură cu valorile celulelor, ci controlează modul în care se comportă fișierul după ce părăsește codul dvs. Protecția foii stabilește ce celule poate edita un utilizator după ce îi transmiteți registrul de lucru. Configurarea paginii stabilește orientarea, dimensiunea hârtiei și marginile. Setările de imprimare (rândurile de titlu repetate, scalarea și întreruperile manuale de pagină) controlează modul în care un tabel de lungime arbitrară apare pe hârtie. Niciuna dintre cele trei setări nu este vizibilă la o primă analiză a datelor într-un vizualizator, pero toate trei se pot defecta neobservat în producție dacă sunt incorecte. HotXLS, o bibliotecă nativă de foi de calcul pentru Delphi și C++Builder, expune complet aceste opțiuni pentru formate .xls și .xlsx, reproducând fiecare regulă Excel mai puțin intuitivă integrată în aceste formate
Prima dintre aceste reguli îi pune în dificultate pe majoritatea dezvoltatorilor la prima protejare a unei foii generate. Apelați Protect și brusc nimeni nu mai poate scrie în nicio celulă, inclusiv în coloanele de introducere a datelor pe baza cărora ați construit registrul. Nimic din codul dvs. nu a atins acele coloane, acesta fiind exact motivul pentru care se întâmplă
Fiecare celulă este implicit blocată
Standardul ECMA-376 definește parametrul locked ca parte a înregistrării de formatare a unei celule, nu ca o proprietate a protecției propriu-zise, iar valoarea sa implicită este true. Protecția foii este doar comutatorul care face ca acest marcaj să poată fi aplicat. Astfel, întregul tabel conține un marcaj de blocare inactiv din momentul în care este creat, iar apelul Protect le activează pe toate deodată. Soluția este stabilirea ordinii în mod deliberat: construiți structura, deblocați explicit intervalele pe care utilizatorii trebuie să le editeze și aplicați protecția la final
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;
Metoda SetFormulaHidden realizează o operațiune diferită și ușor de trecut cu vederea: în timp ce protecția este active, celula afișează în continuare valoarea calculată, însă bara de formule nu arată nimic. Acest lucru contează atunci când o formulă conține tarife de facturare, marje sau ponderi de scor pe care nu doriți să le dezvăluiți fiecărui destinatar care dă clic pe un total. În structura XLS, aceeași intenție este exprimată pentru fiecare interval prin intermediul proprietăților IXLSRange.Locked și FormulaHidden. Foaia de calcul conține de asemenea cincisprezece marcaje Allow* (AllowSort, AllowAutoFilter, AllowFormatCells și restul), astfel încât o foaie protejată să poată fi sortată și filtrată în continuare, fără a fi complet blocată
Ce protejează de fapt parola de protecție
Ambele formate stochează parola de protecție a foii și a registrului ca un hash vechi de 4 cifre hexazecimale. Un format de șaisprezece biți înseamnă că numeroase șiruri de caractere pot corespunde oricărei parole, iar instrumentele de eliminare sunt la o simplă căutare distanță. Tratați protecția ca pe o centură de siguranță împotriva editărilor accidentale, nu ca pe un control al accesului. Este instrumentul potrivit pentru a împiedica utilizatorii să scrie peste coloana de formule și cel mai puțin potrivit pentru tot ceea ce presupune confidențialitate
La un nivel superior, ProtectWorkbook din structura XLSX blochează structura registrului de lucru, ceea ce împiedică adăugarea, redenumirea, ștergerea sau reordonarea foilor. Configurați-o ori de câte ori lista de foi este ea însăși un contract cu un parser din aval care indexează foile după nume sau poziție. O foaie redenumită blochează importul de cealaltă parte la fel ca o coloană ștearsă. Structura XLS reflectă această stratificare prin TXLSWorkbook.Protect la nivel de registru de lucru și prin apelurile Protect pentru fiecare foaie, adăugând proprietatea isProtected pentru codul care trebuie să verifice un fișier moștenit înainte de a-l modifica
Când cerința presupune o confidențialitate reală, mecanismul se schimbă complet. Metoda SaveAsEncrypted generează un pachet criptat AES conform schemei ECMA-376 Standard Encryption, prezentată în detaliu în ghidul despre rezultatele XLSX protejate prin AES, în timp ce structura veche XLS scrie și citește fișiere .xls criptate RC4 prin EncryptionPassword și prin supraîncărcarea cu parolă a metodei Open. Diferența nu este pur teoretică. O foaie protejată circulă ca text clar (cleartext), astfel încât orice instrument zip îi poate citi valorile celulelor, în timp ce un pachet criptat este ilizibil fără parolă. O cerință de audit care prevede că „fișierul de salarii trebuie protejat” înseamnă aproape întotdeauna criptare, indiferent de termenii utilizați
Configurarea paginii face parte din contractul documentului
Comportamentul de imprimare este invizibil pe ecran, motiv pentru care este livrat atât de des cu erori. În momentul în care un client imprimă registrul de lucru sau îl exportă în PDF pentru un auditor, marginile, scalarea și titlurile repetate se transformă în cerințe funcționale pe care nimeni nu le-a testat. În structura XLSX, aceste setări sunt asociate direct foii de calcul:
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;
Două dintre aceste linii ascund capcane. Șirurile de caractere pentru antet și subsol utilizează codurile de formatare ale Excel: &P pentru pagina curentă, &N pentru numărul total, cu &L, &C și &R pentru a defini cele trei secțiuni în mod explicit. Cealaltă capcană este PrintArea, care utilizează în mod deliberat o referință simplă de celulă. HotXLS o stochează necalificată și adaugă ca prefix numele foii atunci când scrie fișierul, astfel încât dacă introduceți manual 'Timesheet!$A$1:$F$60' obțineți o referință dublu calificată și eronată. Aceeași precauție se aplică și la nivelul următor: zonele și titlurile de imprimare sunt salvate ca nume definite predefinite _xlnm.Print_Area și _xlnm.Print_Titles, deci nu adăugați manual înregistrări _xlnm.* prin DefinedNames, altfel cele două mecanisme vor genera conflicte pentru aceeași locație
Scalare care rezistă la volume mari de date
Combinația FitToWidth := 1 cu FitToHeight := 0 se traduce ca: „încadrează întotdeauna coloanele pe o singură pagină lățime, apoi utilizează oricâte pagini pe lungime sunt necesare pentru date”, fiind setarea implicită corectă pentru orice raport cu număr variabil de rânduri. Capcana constă în reglarea unui procent fix sau a unei încadrări pe o pagină pe baza unui fișier de test cu treizeci de rânduri: aplicați aceleași setări la șase sute de rânduri reale, iar rezultatul fie se va împărți pe zeci de pagini trunchiate, fie se va micșora până devine ilizibil. Scalați lățimea, lăsați lungimea să crească și repetați rândul de antet prin PrintTitleRows, astfel încât pagina șaptesprezece să fie în continuare lizibilă de sine stătător
Întreruperile manuale urmează aceeași disciplină de regenerare ca orice alt element dintr-un registru de lucru generat. Metoda AddRowBreak(BeforeRow) începe o pagină nouă înainte de o graniță de secțiune, dar când generatorul rulează din nou și rândurile se deplasează, o întrerupere veche poate ajunge în mijlocul tabelului. Apelați mai întâi ClearAllPageBreaks, apoi adăugați din nou întreruperile calculate pe baza contoarelor de rânduri ale generatorului, în loc să reparați pozițiile vechi. În structura XLS, comenzile echivalente se află în Sheet.PageSetup (orientare, dimensiune hârtie, margini, șiruri de antet și subsol, încadrare în pagini), cu RepeatRows și RepeatColumns acoperind titlurile de imprimare
Verificarea rezultatului înainte ca acesta să ajungă la client
Erorile de protecție și de imprimare au o proprietate comună: sunt simplu de verificat manual, dar aproape niciodată nu sunt testate. Deschideți fișierul generat în Excel și alocați nouăzeci de secunde pentru el. Scrieți într-o celulă de introducere și confirmați că acceptă introducerea; scrieți într-o celulă blocată și confirmați apariția solicitării de protecție; verificați dacă o formulă ascunsă lasă goală bara de formule. Apoi, rulați Print Preview pe un set de date de dimensiuni reale, nu pe un eșantion de treizeci de rânduri, și citiți numărul de pagini, rândul de titlu repetat și numerotarea subsolului. Previzualizarea este pasul care își dovedește utilitatea, deoarece geometria de imprimare depinde de setări care nu sunt redate pe ecran, fiind singurul loc în care devine vizibilă o greșeală de scalare înainte de trimiterea la o imprimantă fizică
O ultimă setare completează această analiză. Funcția FreezePane(ACol, ARow) menține blocul de antet vizibil în timp ce utilizatorul derulează. Acesta este un comportament de ecran, nu de imprimare, însă utilizatorul evaluează întregul document trimis. Iar un registru de lucru care pornește ca o structură definită de un designer obține majoritatea acestor caracteristici în mod automat: fluxul de generare a rapoartelor pe bază de șablon păstrează configurarea paginii în șablon, unde a fost reglată manual pe o imprimantă reală, lăsând codul doar să completeze datele și să aplice din nou protecția după stabilirea structurii
Configurarea foilor din șabloane
HotXLS este o bibliotecă nativă Object Pascal pentru Delphi și C++Builder; documentația completă a interfeței API pentru protecție și configurarea paginii se găsește pe pagina produsului HotXLS Component