Prođite kroz ćelije tek otvorenog šablona izveštaja i spojen naslov se ponaša kao curenje. Pročitate A1 i dobijete „Quarterly Statement”; pročitate B1 do F1, koje vidno stoje pod istom trakom, i ne dobijete ništa. Upišete vrednost u C1 da zakrpite zaglavlje i ona se nikada ne pojavi na ekranu. Mreža nije izgubila vaše podatke. Radi tačno ono što spajanje znači: i u XLS i u XLSX formatu, spojen pravougaonik iscrtava sadržaj jedne ćelije, sidra gore levo, a ostatak tretira kao pokriven prostor koji drži vrednosti, ali ih nikada ne pokazuje. Korisnici Excela to usvoje pokušajem i greškom. Generator izveštaja mora to da zapiše kao pravilo, jer je u generisanom kodu simptom prazna oblast bez izuzetka po kom bi se ušlo u trag. HotXLS, izvorna Object Pascal biblioteka koja iz Delphija i C++Buildera čita i piše oba Excel formata, izlaže tabelu spajanja dovoljno izričito da protiv tog pravila možete da programirate umesto da ga iznova otkrivate u tiketu podrške
Jedna vrednost, jedno sidro
Spajanje je uputstvo za prikaz položeno preko mreže koja ne menja oblik. Svaka pokrivena ćelija i dalje postoji u fajlu kao sopstveno mesto; zapis o spajanju samo govori potrošaču da sadržaj sidra oboji preko pravougaonika. Ta razlika pokreće tri ponašanja koja vredi usvojiti pre nego što napišete ijedan kod za raspored. Čitanje pokrivene ćelije vraća njenu sopstvenu sačuvanu vrednost, koja je kod trake koju ste sami napravili obično prazna, pa svaki kod koji ispituje spojen naslov mora da razreši i pročita sidro. Upis u pokrivenu ćeliju uspeva na nivou fajla i nigde se ne pokazuje, a to je zamka nevidljivog zaglavlja sa početka. A razdvajanje oblasti otkriva sve što je pod njom sedelo sve vreme, pa zalutala vrednost upisana u pokriven prostor postaje vidljiv kvar onog dana kada neko rastvori spajanje
Na strani XLSX-a ta tabela je prvorazredan objekat. Sheet.MergedCells nosi Add('A1:C1'), FindAt(Row, Col), DeleteAt i Items, a poziv za kojim najčešće posežete je FindAt: predajte mu bilo koju koordinatu i vraća spojenu oblast koja pokriva tu ćeliju, ili nil kada ćelija stoji sama. Ta jedna pretraga temelj je za obe polovine ispravnog rada sa spajanjem, za bezbedno čitanje i za stražara nad upisom, a obe se pojavljuju dalje u tekstu
Dve fasade, dva idioma spajanja
HotXLS drži klasičan BIFF8 pogon za .xls i OOXML pogon za .xlsx kao odvojene objektne modele, a spajanje pišu različito jer potiču iz različitih konvencija. XLS fasada sledi Excel COM idiom: uzmete opseg iz indeksiranog svojstva sa dva argumenta i pozovete Merge sa OleVariant vrednošću koja odlučuje kakvu geometriju dobijate
var
Book: IXLSWorkbook; // broji se preko interfejsa: bez ručnog Free
Sh: IXLSWorksheet;
begin
Book := TXLSWorkbook.Create;
Sh := Book.Sheets[1]; // XLS zbirka listova broji od jedan
Sh.Range['A1', 'F1'].Merge(False); // False = jedan spojen blok
Sh.Cells.Item[1, 1].Value := 'Quarterly Statement';
Sh.Range['A3', 'F4'].Merge(True); // True = spajanje po redovima: jedno po redu
Book.SaveAs('layout.xls');
end;
Argument metode Merge je deo koji ljudi pogrešno shvate. Nad opsegom od dva reda, Merge(True) proizvodi dva nezavisna jednoredna spajanja, što je Excelovo „Merge Across” i tačno ono što želite za slojevitu traku zaglavlja čiji redovi treba da ostanu razdvojivi. Merge(False) stapa ceo pravougaonik u jedan blok. Opseg takođe prijavljuje MergeCells kao zastavicu stanja, vraća oblast koja ga sadrži kroz MergeArea i rastvara se pozivom Unmerge. XLSX fasada izlaže iste operacije pod drugim imenima: Sheet.MergeCells(Row1, Col1, Row2, Col2) uzima celobrojne granice, TXLSXRange.Merge prihvata istovetnu Across varijantu, a zbirka MergedCells drži rezultat
Šablon koji raste sa svojim podacima
Pravi šablon izveštaja nije nepromenljiva mreža. Zaglavlje i zbirovi su nepromenljivi, ali se odeljak sa stavkama između njih rasteže do onoga što upit vrati. Obrazac koji izdrži drži jedan potpuno stilizovan red stavke u šablonu, klonira ga po jednom za svaki zapis, a zatim otvara procep ispred bloka zbirova da bi sve usidreno ispod skliznulo naniže bez gubitka svog formatiranja
Sheet.Range['A1:F1'].Merge;
Sheet.Cells[1, 1].Value := 'INVOICE #2026-0611'; // vrednost ide u sidro, A1
Sheet.RowHeight[1] := 28;
TitleFont := Book.Fonts.Add('Calibri', 16, True, False);
Sheet.Cells[1, 1].FontIndex := TitleFont + 1; // zaliha broji od nule, ćelija od jedan
// red 5 je stilizovani red šablona za stavke
for I := 0 to ItemCount - 1 do
Sheet.CopyRange(5, 1, 5, 6, 6 + I, 1); // stilovi i formule putuju sa njim
// otvori procep iznad bloka zbirova; sadržaj ispod se pomera naniže
Sheet.InsertRows(6 + ItemCount, 1);
Sheet.Range['A1:F1'].SetBorders(xlsxEdgeOutline, xlsxBorderMedium);
Dve linije zaslužuju drugi pogled. Dodela fonta nosi grešku za jedan koja nečujno ujeda: Fonts.Add vraća poziciju u zalihi brojanu od nule, dok ćelija čuva referencu na font brojanu od jedan, gde 0 znači podrazumevani font, pa izostavljanje onog + 1 ne podiže ništa, samo vaš naslov stilizuje pogrešnim pismom. Druga linija je CopyRange, koja uz vrednosti nosi i formatiranje i formule. To je ceo razlog da klonirate ručno napravljen red šablona umesto da njegov izgled iznova gradite kodom. Dizajner je vlasnik izgleda jednom, u šablonu; generator samo sipa podatke u njegove kopije
Ta podela ide i dalje kada višekratni raspored živi u sopstvenoj radnoj svesci, recimo kao list sa trakama zaglavlja i podnožja deljenim među izveštajima. CopyRangeTo izvodi isti klon preko granica radnih listova, uzimajući ciljni list i odredišne koordinate, pa generator može da drži jedan netaknut list šablona i da njegove oblase utiskuje u onoliko izlaznih listova koliko posao traži. Alternativa, menjanje šablona na licu mesta uz pokušaj da se posle vrati u prvobitno stanje, spada u ono što radi do dana kada se izvršavanje prekine na pola
Šta InsertRows pomera, a šta ne
Obrazac rastućeg šablona radi samo zato što je XLSX InsertRows strukturna izmena, a ne premetanje ćelija. Kada otvori procep, premešta spojene oblasti, visine redova, hiperveze, komentare, zamrznuta okna, opsege automatskog filtera, uslovna formatiranja, validacije podataka, tabele, definisana imena, sidra slika i sidra grafikona koji sede ispod tačke umetanja, a ne samo vrednosti ćelija. To je ono što bloku zbirova omogućava da stigne u svoj novi red sa netaknutim spajanjima i formatima brojeva umesto da stigne ogoljen
Dva njegova dokumentovana ograničenja su ona oko kojih treba projektovati. Prilagođavanje formula ograničeno je na list koji se uređuje: reference unutar tog lista se prepisuju, a prepisuje se i formula na drugom listu koja pokazuje u pomerenu oblast, ali prilagođavanje prati samo reference koje ciljaju uređivani list, pa svaka šema referenci preko radnih sveski zaslužuje sopstvenu proveru umesto slepog poverenja. Drugo ograničenje je oštrije i tiče se XLS strane. Pivot tabele preživljavaju cikluse otvaranja i čuvanja kao sirovi očuvani zapisi, a ne kao modelovani objekti koje HotXLS može da pomera, pa umetanje redova ne premešta otisak pivota. Svaki šablon koji pravite za .xls format treba da svoje pivot oblasti parkira daleko od bilo koje trake koja raste
Odbijanje upisa podataka u prostor rasporeda
Otkaz sa spojenim ćelijama koji zaista stigne u produkciju nije onaj kozmetički. On je strukturni: red sa stavkom odluta u spojenu traku rasporeda, njegove vrednosti slete u pokrivene ćelije i postanu nevidljive, a zbirovi kolona tiho prestanu da odgovaraju onome što svako ko čita list može da vidi. Pošto FindAt za bilo koju koordinatu odgovara na pitanje o pokrivajućoj oblasti, generator taj upis može da odbije u trenutku kada bi se desio umesto da isporuči izveštaj koji nečujno broji manje
// odbij upis podataka stavke u spojenu oblast rasporeda
if Sheet.MergedCells.FindAt(Row, 1) <> nil then
raise Exception.CreateFmt('row %d overlaps a merged layout region', [Row]);
Sheet.Cells[Row, 1].Value := Detail.Description;
Ista granična provera pripada svuda gde će korisnik kasnije sortirati ili filtrirati izlaz. Opseg sa spajanjima u sebi ne može čisto da se sortira, jer sortiranje pomera redove nezavisno, a spajanje koje se proteže preko redova nema jedan red sa kojim bi putovalo; Excel na to odgovara greškom ili izlomljenim rasporedom. Disciplina koja izveštaje drži ispravnim je geografska. Zatvorite spajanja u trake naslova, razdelnike odeljaka i blokove za potpis, a tabelarnu sredinu lista držite ravnom. Članak o generisanju izveštaja iz šablona razvija ovu podelu na raspored i podatke u pun tok rada vođen čuvarima mesta, a članak o uslovnom formatiranju i bogatom tekstu pokriva stilizovanje te ravne trake podataka
Kako spajanja slabe na izlazu
Spajanje je pojam radne sveske, a svaki tekstualno usmeren format izvoza poštuje ga u različitoj meri. Poznavanje ta tri ponašanja unapred štedi jedan krug provere kvaliteta. Izvoz u HTML verno reprodukuje spajanja, emitujući colspan i rowspan u jednoj tabeli, pa izveštaj namenjen pregledaču zadržava svoj trakasti izgled. Izvoz u RTF uopšte ne prostire kolone: tekst sidra sleti u svoju ćeliju, a preostala širina spajanja izađe kao prazne ćelije, što širok naslov u obrađivaču teksta vizuelno gurne ulevo. CSV nema pojam spajanja, pa vrednost sidra zauzme jedno polje, a svaka pokrivena ćelija izađe kao prazno polje. Zaključak za radnu svesku koja hrani i razdvojene izvoze jeste da sve noseće držite van spojene geometrije; članak o izvozu u CSV, TSV i HTML detaljno prolazi kroz svaki format
Jedna uteha za svakoga ko ovo vaga naspram veličine fajla: spajanja na razmeri izveštaja koštaju gotovo ništa. Tabela spajanja je sićušna pored podataka ćelija, a čitanje pokrivene ćelije i dalje ide kroz FindAt, a ne kroz pretraživanje. Pritisak na performanse kod velikih radnih sveski dolazi sa druge strane, uglavnom od rasta zalihe stilova i memorije koju drži putanja čuvanja, čime se neposredno bavi članak o performansama velikih radnih sveski. Oba API-ja za spajanje, operacije strukturnog uređivanja i demoi šablona stižu uz HotXLS Delphi Component