Prođite kroz ćelije tek otvorenog šablona izveštaja i spojeni naslov će se ponašati poput curenja podataka. Čitate A1 i dobijate "Quarterly Statement", a kada čitate od B1 do F1, koji očigledno stoje pod istim natpisom, ne dobijate ništa. Upišite vrednost u C1 da biste izmenili zaglavlje i ona se nikada neće pojaviti na ekranu. Mreža nije izgubila vaše podatke. Ona radi tačno ono što spajanje (merge) podrazumeva: i u XLS i u XLSX formatu, spojeni pravougaonik renderuje sadržaj jedne ćelije — gornjeg levog sidra (anchor) — a ostatak tretira kao pokriveni prostor koji sadrži vrednosti ali ih nikada ne prikazuje. Korisnici Excel-a ovo nauče kroz pokušaje i greške. Generator izveštaja to mora da kodira kao pravilo, jer je u generisanom kodu simptom prazna regija bez ikakvog izuzetka koji bi ukazao na problem. HotXLS, izvorna Object Pascal biblioteka koja čita i piše oba Excel formata iz Delphi-ja i C++Builder-u, izlaže tabelu spajanja dovoljno eksplicitno da možete programirati u skladu sa ovim pravilom, umesto da ga ponovo otkrivate kroz tikete podrške
Jedna vrednost, jedno sidro
Spajanje je instrukcija za prikaz postavljena preko mreže koja ne menja svoj oblik. Svaka pokrivena ćelija i dalje postoji u fajlu kao sopstveni slot; zapis o spajanju samo govori programu za prikaz da iscrta sadržaj sidra preko čitavog pravougaonika. Ta razlika upravlja trima ponašanjima koja vredi usvojiti pre nego što napišete bilo kakav kod za raspored. Čitanje pokrivene ćelije vraća njenu sopstvenu sačuvanu vrednost, koja je za natpis koji ste napravili obično prazna, tako da svaki kod koji proverava spojeni naslov mora da razreši i pročita sidro. Upisivanje u pokrivenu ćeliju uspeva na nivou fajla, ali se nigde ne prikazuje, što je zamka nevidljivog zaglavlja pomenuta na početku. A razdvajanje (unmerging) regije otkriva šta god da je sedelo ispod nje sve vreme, tako da zalutala vrednost upisana u pokriveni prostor postaje vidljiv nedostatak onog dana kada neko ukine spajanje
Dve fasade, dva idioma spajanja
HotXLS drži klasični BIFF8 .xls mehanizam i OOXML .xlsx mehanizam kao odvojene modele objekata, i oni drugačije zapisuju spajanje jer potiču iz različitih konvencija. XLS fasada prati Excel COM idiom: uzimate opseg (range) iz indeksiranog svojstva sa dva argumenta i pozivate metodu Merge sa parametrom OleVariant čija vrednost određuje geometriju koju na kraju dobijate
var
Book: IXLSWorkbook; // interface-counted: no manual Free
Sh: IXLSWorksheet;
begin
Book := TXLSWorkbook.Create;
Sh := Book.Sheets[1]; // XLS sheet collection is 1-based
Sh.Range['A1', 'F1'].Merge(False); // False = one merged block
Sh.Cells.Item[1, 1].Value := 'Quarterly Statement';
Sh.Range['A3', 'F4'].Merge(True); // True = merge across: one merge per row
Book.SaveAs('layout.xls');
end;
Argument metode Merge je deo koji ljudi pogrešno shvataju. Preko opsega od dva reda, Merge(True) proizvodi dva nezavisna spajanja od po jednog reda, što je Excel-ova opcija "Spajanje preko" (Merge Across) i upravo ono što želite za naslaganu traku zaglavlja koja bi trebalo da zadrži svoje redove odvojenim. Poziv Merge(False) spaja čitav pravougaonik u jedan blok. Opseg takođe prijavljuje MergeCells kao zastavicu stanja, vraća regiju koja ga sadrži preko MergeArea i razdvaja se pomoću metode Unmerge. XLSX fasada izlaže iste operacije pod različitim nazivima: Sheet.MergeCells(Row1, Col1, Row2, Col2) uzima celobrojne granice, TXLSXRange.Merge prihvata ekvivalentnu Across varijantu, a kolekcija MergedCells čuva rezultat
Šablon koji raste sa svojim podacima
Stvarni šablon izveštaja nije fiksna mreža. Zaglavlje i ukupne vrednosti su fiksni, ali se odeljak sa detaljima između njih rasteže na šta god upit vrati. Obrazac koji se održava drži jedan potpuno stilizovan red sa detaljima u šablonu, klonira ga jednom po zapisu, a zatim otvara prazninu ispred bloka sa ukupnim vrednostima kako bi sve što je sidreno ispod skliznulo nadole bez gubljenja svog formatiranja
Sheet.Range['A1:F1'].Merge;
Sheet.Cells[1, 1].Value := 'INVOICE #2026-0611'; // value goes to the anchor, A1
Sheet.RowHeight[1] := 28;
TitleFont := Book.Fonts.Add('Calibri', 16, True, False);
Sheet.Cells[1, 1].FontIndex := TitleFont + 1; // pool index 0-based, cell side 1-based
// row 5 is the styled detail template line
for I := 0 to ItemCount - 1 do
Sheet.CopyRange(5, 1, 5, 6, 6 + I, 1); // styles and formulas travel with it
// open a gap above the totals block; content below shifts down
Sheet.InsertRows(6 + ItemCount, 1);
Sheet.Range['A1:F1'].SetBorders(xlsxEdgeOutline, xlsxBorderMedium);
Dve linije zaslužuju pažnju. Dodeljivanje fonta nosi grešku "off-by-one" (razlika za jedan) koja prolazi tiho: Fonts.Add vraća poziciju u bazi od 0, dok ćelija čuva referencu fonta u bazi od 1 gde 0 označava podrazumevani font, tako da izostavljanje + 1 ne podiže nikakvu grešku, već samo stilizuje vaš naslov pogrešnim fontom. Druga linija je CopyRange, koja prenosi formatiranje i formule zajedno sa vrednostima. To je čitav razlog za kloniranje ručno napravljenog reda šablona umesto ponovnog konstruisanja njegovog izgleda u kodu. Dizajner jednom definiše izgled u šablonu, a generator samo sipa podatke u njegove kopije
Taj split se dalje širi kada se višekratno upotrebljivi raspored nalazi u sopstvenoj radnoj svesci, recimo list sa trakama zaglavlja i podnožja koji se dele između izveštaja. Metoda CopyRangeTo vrši isto kloniranje preko granica radnih listova, uzimajući ciljni list i odredišne koordinate, tako da generator može da zadrži jedan netaknuti šablonski list i utisne njegove delove na onoliko izlaznih listova koliko posao zahteva. Alternativa — izmena šablona na licu mesta i pokušaj njegovog kasnijeg vraćanja — je vrsta stvari koja radi sve dok se proces ne prekine na pola puta
Šta InsertRows pomera, a šta ne
Obrazac rasta šablona radi samo zato što je InsertRows na XLSX strani strukturna izmena, a ne obično mešanje ćelija. Kada otvori prazninu, on premešta spojene regije, visine redova, hiperveze, komentare, zamrznuta polja, opsege auto-filtera, uslovne formate, validacije podataka, tabele, definisana imena, sidra slika i sidra grafikona koji se nalaze ispod tačke ubacivanja, a ne samo vrednosti ćelija. To je ono što omogućava bloku sa ukupnim vrednostima da stigne na svoj novi red sa netaknutim spajanjima i formatima brojeva, umesto da stigne potpuno ogoljen
Njegova dva dokumentovana ograničenja su ona oko kojih treba projektovati sistem. Prilagođavanje formula je ograničeno na list koji se uređuje: reference unutar tog lista se prepisuju, a formula na drugom listu koja pokazuje na pomerenu oblast se takođe prepisuje, ali prilagođavanje prati samo reference koje ciljaju uređeni list, tako da svaka šema referenciranja između radnih svezaka zaslužuje sopstvenu reviziju, a ne slepo poverenje. Drugo ograničenje je još oštrije i nalazi se na XLS strani. Pivot tabele preživljavaju cikluse otvaranja i čuvanja kao sirovi sačuvani zapisi, a ne kao modelovani objekti koje HotXLS može da pomera, pa ubacivanje redova ne premešta otisak pivot tabele. Svaki šablon koji pravite za .xls format trebalo bi da postavi svoje pivot regije daleko od bilo koje trake koja raste
Odbijanje upisa podataka u prostor rasporeda (layout)
Problem sa spojenim ćelijama koji zapravo stiže do produkcije nije kozmetičke prirode. On je strukturne prirode: red sa detaljima skrene u spojenu traku rasporeda, njegove vrednosti završe u pokrivenim ćelijama i postanu nevidljive, a ukupne vrednosti kolona tiho prestanu da se poklapaju sa onim što svako ko čita list može da vidi. Pošto metoda FindAt daje odgovor o pokrivenoj regiji za bilo koju koordinatu, generator može da odbije taj upis u trenutku kada bi se desio, umesto da isporuči izveštaj koji tiho prikazuje manji broj od stvarnog
Ista provera granica pripada bilo kom mestu gde će korisnik kasnije sortirati ili filtrirati izlaz. Opseg koji sadrži spajanja unutar sebe ne može se čisto sortirati, jer sortiranje pomera redove nezavisno, a spajanje koje se proteže kroz više redova nema jedan red sa kojim bi putovalo; Excel reaguje greškom ili poremećenim rasporedom. Disciplina koja održava izveštaje ispravnim je geografska. Ograničite spajanja na trake sa naslovima, razdelnike odeljaka i blokove za potpis, a tabelarnu sredinu lista držite ravnom. Članak o generisanju izveštaja na osnovu šablona razvija ovu podelu na raspored nasuprot podataka u potpuni radni tok vođen mestima za unos, a članak o uslovnom formatiranju i bogatom tekstu pokriva stilizovanje te ravne trake sa podacima
Kako spajanja degradiraju na izlazu
Spajanje je koncept radne sveske, i svaki izvozni format orijentisan na tekst ga poštuje u različitoj meri. Poznavanje ova tri ponašanja unapred štedi jedan QA ciklus. Izvoz u HTML verno reprodukuje spajanja, emitujući colspan i rowspan na jednoj tabeli, tako da izveštaj namenjen veb pregledaču zadržava svoj trakasti izgled. Izvoz u RTF uopšte ne spaja kolone: tekst sidra završava u sopstvenoj ćeliji, a preostala širina spajanja izlazi kao prazne ćelije, što ostavlja širok naslov vizuelno gurnut ulevo u procesoru teksta. CSV nema koncept spajanja, pa vrednost sidra zauzima jedno polje, a svaka pokrivena ćelija izlazi kao prazno polje. Zaključak za radnu svesku koja takođe hrani razgraničene izvoze jeste da drži sve važne podatke van spojene geometrije; članak o izvozu u CSV, TSV i HTML detaljno opisuje svaki format
Jedno olakšanje za svakoga ko ovo meri u odnosu na veličinu fajla: spajanja ne koštaju skoro ništa na skali izveštaja. Tabela spajanja je sićušna pored podataka o ćelijama, a čitanje pokrivene ćelije i dalje ide kroz FindAt umesto skeniranja celog lista. Pritisak na performanse kod velikih radnih svezaka dolazi sa drugih mesta, uglavnom od rasta baze stilova (style-pool) i memorije koju zauzima putanja čuvanja, što članak o performansama velikih radnih svezaka direktno obrađuje. Oba API-ja za spajanje, operacije strukturnog uređivanja i demo primeri šablona isporučuju se sa HotXLS komponentom