Articol tehnic

HotXLS: protecția foii, configurarea paginii și tipărirea

Trei grupuri de setări ale foii nu au nimic de-a face cu valorile din celule și totul de-a face cu felul în care se comportă fișierul odată ce iese din codul dumneavoastră. Protecția foii decide ce celule poate edita un utilizator după ce predați registrul de lucru. Configurarea paginii fixează orientarea, dimensiunea hârtiei și marginile. Setările de tipărire (rânduri de titlu repetate, scalare și întreruperi manuale de pagină) controlează cum aterizează pe hârtie o grilă de lungime arbitrară. Niciuna dintre cele trei nu se vede când priviți datele într-un vizualizator, iar toate trei se strică în tăcere pe teren atunci când sunt greșite. HotXLS, o bibliotecă nativă de foi de calcul pentru Delphi și C++Builder, expune întreaga suprafață pentru .xls și .xlsx, ceea ce înseamnă că reproduce și fiecare regulă Excel contraintuitivă coaptă în acea suprafață

Prima dintre acele reguli îi pune piedică aproape oricui, prima dată când protejează o foaie generată. Apelați Protect și deodată nimeni nu mai poate scrie în nicio celulă, inclusiv în coloanele de intrare în jurul cărora ați construit registrul. Nimic din codul dumneavoastră nu a atins acele coloane, și exact de aceea se întâmplă

Fiecare celulă se naște blocată

ECMA-376 definește locked ca parte a înregistrării de formatare a unei celule, nu ca proprietate a protecției în sine, iar valoarea implicită este true. Protecția foii este doar comutatorul care face indicatorul să poată fi impus. Așadar toată grila poartă un indicator de blocare din clipa în care există, adormit, iar apelul lui Protect le activează pe toate deodată. Remedierea este să stabiliți ordinea în mod deliberat: construiți aspectul, deblocați explicit intervalele pe care utilizatorii trebuie să le editeze și protejați la final

Diagramă a ordinii de protecție HotXLS în Delphi, în care fiecare celulă se naște cu locked true, intervalele de intrare sunt deblocate mai întâi cu SetLocked, iar Sheet.Protect apelat la final păstrează editabile celulele deblocate
Celulele sosesc blocate implicit, deci deblocați mai întâi intervalele de intrare și apelați Protect la final, ca să rămână editabile
Book := TXLSXWorkbook.Create;
try
  Sheet := Book.Sheets.Add('Timesheet');
  // ... rândul de antet, coloana de nume și formulele de tarif se scriu aici ...
  Sheet.Range['B2:B50'].SetLocked(False);         // aici își trec angajații orele
  Sheet.Range['F2:F50'].SetFormulaHidden(True);   // păstrați privat calculul tarifului
  Sheet.Protect('review-2026');                   // acum mușcă indicatorii de blocare
  Book.SaveAs('timesheet.xlsx');
finally
  Book.Free;
end;

SetFormulaHidden face ceva separat și ușor de trecut cu vederea: cât timp protecția este activă, celula își arată în continuare valoarea calculată, dar bara de formule nu arată nimic. Asta contează când o formulă înglobează tarife de facturare, marje sau ponderi de punctaj pe care ați prefera să nu le dați fiecărui destinatar care dă clic pe un total. Pe fațada XLS, aceeași intenție este exprimată per interval prin IXLSRange.Locked și FormulaHidden. Foaia de acolo poartă și cincisprezece indicatori Allow* (AllowSort, AllowAutoFilter, AllowFormatCells și restul), deci o foaie protejată poate fi totuși sortată și filtrată, în loc să fie înghețată într-un exponat sigilat

Ce protejează de fapt parola de protecție

Ambele formate stochează parola de protecție a foii și a registrului ca un hash clasic de 4 cifre hexazecimale. Șaisprezece biți înseamnă că nenumărate șiruri se ciocnesc cu orice parolă dată, iar uneltele de eliminare sunt la o căutare distanță. Tratați protecția ca pe o centură de siguranță împotriva editărilor accidentale, nu ca pe un control de acces. Este unealta potrivită ca să oprească recenzenții să scrie peste coloana de formule și unealta greșită pentru orice implică cuvântul confidențial

Cu un nivel mai sus, ProtectWorkbook de pe fațada XLSX blochează structura registrului, ceea ce împiedică adăugarea, redenumirea, ștergerea sau reordonarea foilor. Setați-o ori de câte ori lista de foi este ea însăși un contract cu un analizor din aval care indexează foile după nume sau poziție. O foaie redenumită strică importul de partea cealaltă la fel de sigur ca o coloană ștearsă. Fațada XLS oglindește stratificarea prin TXLSWorkbook.Protect la nivel de registru și apeluri Protect per foaie, plus o proprietate isProtected pentru codul care trebuie să inspecteze un fișier moștenit înainte de a modifica ceva

Când cerința este confidențialitate reală, mecanismul se schimbă complet. SaveAsEncrypted produce un pachet criptat AES sub schema Standard Encryption din ECMA-376, tratată în detaliu în ghidul de ieșire XLSX protejată cu AES, iar fațada XLS clasică scrie și citește fișiere .xls criptate RC4 prin EncryptionPassword și supraîncărcarea cu parolă a lui Open. Diferența nu este academică. O foaie protejată călătorește în clar, deci orice unealtă zip îi poate citi valorile din celule, în timp ce un pachet criptat este ilizibil fără parolă. O linie de audit care spune „fișierul de salarii trebuie protejat” înseamnă aproape întotdeauna criptare, indiferent de vocabularul pe care se întâmplă să îl folosească

Diagramă care contrastează protecția foii din HotXLS, care stochează un hash clasic de 16 biți și lasă valorile celulelor în clar, lizibile de orice unealtă zip, cu ieșirea AES produsă de SaveAsEncrypted, care rămâne ilizibilă fără parolă
Protecția foii este o centură de siguranță împotriva editărilor accidentale, în timp ce valorile în clar rămân lizibile, iar doar criptarea AES ascunde conținutul

Configurarea paginii face parte din contractul documentului

Comportamentul la tipărire este invizibil pe ecran, motiv pentru care ajunge stricat în producție atât de des. În clipa în care un client tipărește registrul, sau îl exportă în PDF pentru un auditor, marginile, scalarea și titlurile repetate devin cerințe funcționale pe care nu le-a testat nimeni. Pe fațada XLSX, aceste setări atârnă direct de foaie:

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';     // referință simplă: fără nume de foaie aici
Sheet.PrintTitleRows := '$1:$1';     // rândul de antet se repetă pe fiecare pagină
Sheet.FitToWidth := 1;
Sheet.FitToHeight := 0;              // crește în jos pe măsură ce cresc datele
Sheet.PrintGridlines := False;

Două dintre acele linii ascund capcane. Șirurile de antet și de subsol folosesc codurile de formatare din Excel: &P pentru pagina curentă, &N pentru numărul total, cu &L, &C și &R pentru a adresa explicit cele trei secțiuni. Cealaltă capcană este PrintArea, care primește intenționat o referință simplă de celule. HotXLS o stochează necalificată și prefixează numele foii când scrie fișierul, deci dacă transmiteți dumneavoastră 'Timesheet!$A$1:$F$60' produceți o referință dublu calificată și malformată. Aceeași precauție se aplică cu un strat mai jos: zonele de tipărire și titlurile de tipărire sunt păstrate ca numele definite încorporate _xlnm.Print_Area și _xlnm.Print_Titles, deci nu adăugați niciodată manual intrări _xlnm.* prin DefinedNames, altfel cele două mecanisme se vor bate pe același loc

Scalare care supraviețuiește volumelor de date din producție

Combinația FitToWidth := 1 cu FitToHeight := 0 se citește ca „încadrează întotdeauna coloanele pe lățimea unei pagini, apoi ia câte pagini în jos are nevoie datele” și este valoarea implicită corectă pentru orice raport al cărui număr de rânduri variază. Capcana este să reglați un procent fix sau o pereche de încadrare pe pagină față de un fișier de test de treizeci de rânduri: dați acelorași setări șase sute de rânduri de producție și ieșirea fie explodează în zeci de pagini tăiate, fie se micșorează sub pragul lizibilității. Scalați lățimea, lăsați lungimea să crească și repetați rândul de antet prin PrintTitleRows, ca pagina șaptesprezece să rămână lizibilă pe cont propriu

Diagramă a scalării la tipărire în HotXLS pentru Delphi, cu FitToWidth setat la 1 pentru ca fiecare pagină să rămână lată cât o foaie, FitToHeight setat la 0 pentru ca paginile să crească în jos, PrintTitleRows repetând banda de antet și întreruperi de pagină regenerate după ClearAllPageBreaks
FitToWidth 1 cu FitToHeight 0 menține fiecare pagină lată cât o foaie, în timp ce rândurile de titlu repetate și întreruperile regenerate păstrează lizibilitatea

Întreruperile manuale urmează aceeași disciplină de regenerare ca orice altceva dintr-un registru generat. AddRowBreak(BeforeRow) începe o pagină nouă înaintea unei limite de secțiune, dar când generatorul rulează din nou și rândurile se deplasează, o întrerupere învechită aterizează în mijlocul tabelului. Apelați mai întâi ClearAllPageBreaks, apoi readăugați întreruperi calculate din propriile contoare de rânduri ale generatorului, în loc să peticiți poziții vechi. Pe fațada XLS, controalele echivalente stau pe Sheet.PageSetup (orientare, dimensiune de hârtie, margini, șiruri de antet și subsol, încadrare pe pagini), cu RepeatRows și RepeatColumns acoperind titlurile de tipărire

Verificarea rezultatului înaintea clientului

Defectele de protecție și de tipărire au o proprietate comună: sunt banal de verificat manual și aproape niciodată verificate. Deschideți fișierul generat în Excel și acordați-i nouăzeci de secunde. Scrieți într-o celulă de intrare și confirmați că acceptă tastarea; scrieți într-o celulă blocată și confirmați că apare solicitarea de protecție; verificați că o formulă ascunsă lasă bara de formule goală. Apoi rulați Print Preview pe un set de date de mărime de producție, nu pe un eșantion de treizeci de rânduri, și citiți numărul de pagini, rândul de titlu repetat și numerotarea din subsol. Previzualizarea este pasul care se plătește singur, pentru că geometria de tipărire depinde de setări fără nicio randare pe ecran, iar în lipsa unei imprimante fizice este singurul loc în care o greșeală de scalare devine vreodată vizibilă

O ultimă setare completează revizuirea. FreezePane(ACol, ARow) menține blocul de antet în câmpul vizual în timp ce un recenzent derulează. Acesta este comportament de ecran, nu de tipărire, dar un recenzent judecă tot livrabilul deodată. Iar un registru care își începe viața ca aspect întreținut de un designer primește mare parte din toate acestea gratis: fluxul de generare de rapoarte din șablon ține configurarea paginii în șablon, unde un om a reglat-o față de o imprimantă reală, și lasă codul să umple datele și să reaplice protecția după ce aspectul se așază

HotXLS este o bibliotecă nativă de foi de calcul în Object Pascal pentru Delphi și C++Builder; referința completă a API-ului de protecție și de configurare a paginii se află pe pagina de produs HotXLS Delphi Component