HotXLS isporučuje TXLSWorkbookViewer, izvorni VCL kontrolni element koji prikazuje radne sveske XLS, XLSX, XLSM i ODS kao interaktivnu mrežu preglednice unutar Delphi ili C++Builder obrasca, bez instaliranja Excela ili upravljanja njime preko OLE automatizacije. Kvalitetna izrada takvog kontrolnog elementa zahteva rešavanje tri konkretna problema: preslikavanje klika mišem koji pada unutar spojene ćelije na ispravnu logičku ćeliju, održavanje usklađenosti položaja pomeranja, zaglavlja i izbora ćelije dok korisnik pomera list mnogo veći od vidljivog prozora i određivanje šta klik na oznaku komentara ili ćeliju hiperveze zaista treba da uradi
Većina Delphi timova koristi preglednik preglednica iz razloga koji nemaju veze sa uređivanjem: revizijska stanica koja pregleda otpremljene radne sveske pre ulaska u tok obrade, kiosk ili preglednik izveštaja u kojem Microsoft Office nije deo instalacije ili QA alat koji mora da prikaže sadržaj radne sveske bez nepredvidivosti upravljanja stvarnim Excel procesom preko COM-a. Obična mreža nizova brzo prikaže tekst u ćelijama, ali datoteka preglednice nije obična mreža: ćelije se spajaju u blokove koji postoje tek u osnovnom modelu, listovi imaju fiksna zaglavlja i nezavisne horizontalne i vertikalne položaje pomeranja, a pojedinačne ćelije sadrže komentare i hiperveze kojima je potreban sopstveni model interakcije. TXLSWorkbookViewer je HotXLS-ov odgovor na taj nedostatak, a njegov unutrašnji dizajn predstavlja razuman nacrt za svakoga ko sličan kontrolni element izrađuje od početka
Kako preglednik radne sveske izbegava zavisnost od Excela
TXLSWorkbookViewer u potpunosti izbegava Excel tako što čita kroz sopstveni obrađeni objektni model HotXLS-a, umesto da otvara dokument kroz Excel i upravlja njime. Svojstvo Workbook povezuje postojeći TXLSWorkbook za klasične XLS datoteke, a XlsxWorkbook povezuje TXLSXWorkbook za XLSX, XLSM i varijante predložaka; bilo koji od njih može već biti otvoren na drugom mestu u aplikaciji, a preglednik ga samo čita. Kada kontrolni element treba sam da upravlja datotekom, LoadFromFile proverava ekstenziju, usmerava XLSX, XLSM, XLTX, XLTM i ODS kroz savremeni mehanizam, a sve ostalo kroz klasični, pa oslobađa radnu svesku koju je kreirao kada se kontrolni element očisti ili uništi
var
Viewer: TXLSWorkbookViewer;
Book: TXLSXWorkbook;
begin
Book := TXLSXWorkbook.Create;
if Book.Open('quarterly-report.xlsx') <> 1 then
raise Exception.Create('Could not open workbook');
Viewer := TXLSWorkbookViewer.Create(Self);
Viewer.Parent := Self;
Viewer.Align := alClient;
Viewer.XlsxWorkbook := Book; // the viewer does not take ownership
Viewer.GoToCell(1, 1);
Caption := Viewer.WorksheetName + ': ' + Viewer.SelectedCellText;
end;
Pronalaženje ispravne ćelije unutar spojenog opsega
Razrešavanje klika na ispravnu ćeliju u TXLSWorkbookViewer odvija se u dve faze, a ta podela je važna zato što su geometrija piksela i semantika preglednice zaista različiti problemi. Prva faza je čista geometrija: privatna metoda CellAtPoint prolazi kroz širine kolona i visine redova od trenutnog položaja pomeranja dok ne pronađe pojas koji sadrži kliknute X i Y koordinate, bez ikakvog znanja o spojenim ćelijama. Druga faza je semantička: svaki put koji menja izbor, bilo da je to klik mišem, taster sa strelicom, Tab ili direktan poziv GoToCell, prolazi kroz jednu internu rutinu ChangeSelection, koja normalizuje sirovi red i kolonu prema svakom spajanju i postavlja ih na sidrenu ćeliju spajanja pre nego što se izbor zaista promeni
Sidro je gornja leva ćelija spojenog opsega i jedina je ćelija u tom bloku koja u osnovnom modelu radne sveske zaista sadrži vrednost, format, komentar ili hipervezu; svaka druga ćelija koju spajanje vizuelno pokriva prazna je u samim podacima. Kod klasičnih XLS radnih svezaka sidro potiče iz Cell.MergeArea, odnosno IXLSRange čiji Row i Column pokazuju na vlasničku ćeliju; kod XLSX i ODS radnih svezaka MergedCells.FindAt vraća TXLSXMergedRange koji isto sidro izlaže kao Row1 i Col1. Iscrtavanje nezavisno rešava srodan problem tako što proširuje pravougaonik spojene ćelije preko punog raspona redova i kolona i preskače ćelije unutar tog raspona, pa okvir izbora obuhvata ceo spojeni blok umesto samo ugla sidra, dok je upisivanje spojenih rasporeda, a ne samo njihovo čitanje, povezan ali odvojen problem obrađen u pratećem članku o rasporedu spojenih ćelija za predloške izveštaja
var
Sheet: TXLSXWorksheet;
begin
Sheet := Book.Sheets.Add('Summary');
Sheet.MergeCells(2, 2, 3, 4); // B2:D3
Sheet.Cells[2, 2].Value := 'Region totals';
Viewer.XlsxWorkbook := Book;
Viewer.GoToCell(3, 4); // targets the bottom-right corner of the merge
// SelectedRow is now 2 and SelectedCol is now 2: normalized to the anchor cell
end;
Šta održava usklađenost pomeranja, zaglavlja i izbora
TXLSWorkbookViewer održava usklađenim tri odvojena dela stanja: logički položaj pomeranja u TopRow i LeftCol, izvorne Windows trake za pomeranje koje kontrolni element zahteva kroz WS_HSCROLL i WS_VSCROLL u CreateParams i trenutni izbor u SelectedRow i SelectedCol. Prevlačenje trake za pomeranje ili okretanje točkića miša pokreće WM_HSCROLL, WM_VSCROLL ili WM_MOUSEWHEEL, koji ažuriraju TopRow ili LeftCol i ponovo iscrtavaju sadržaj; izbor se ne pomera, što odgovara načinu na koji sam Excel razdvaja pomeranje prikaza od izbora. Posle svakog od tih ažuriranja UpdateScrollBars vraća novi položaj u izvornu traku za pomeranje preko SetScrollInfo, pa klizač nikada ne gubi usklađenost sa onim što mreža zaista prikazuje
Navigacija tastaturom sprovodi istu sinhronizaciju u suprotnom smeru: kada izbor pređe ivicu vidljive mreže, EnsureSelectionVisible pomera TopRow ili LeftCol sabiranjem stvarnih širina kolona i visina redova umesto prostog povećanja za jedan, jer redovi i kolone mogu imati prilagođene veličine, a zatim poziva UpdateScrollBars tako da klizač odražava mesto na koje je tastatura upravo pomerila prikaz. Pojasevi zaglavlja sa brojevima redova i slovima kolona, čije veličine određuju RowHeaderWidth i ColumnHeaderHeight, deo su ovog kontrolnog elementa koji ostaje pričvršćen za ekran dok TopRow i LeftCol pomeraju podatke ispod njega, i to je ceo obim zamrzavanja koji kontrolni element sam sprovodi: to nije Excelova funkcija zamrzavanja okana i ne postoji ugrađen način da se proizvoljni red ili kolona podataka pričvrste dok ostatak lista prolazi pored njih. Jednu granicu vredi testirati pre isporuke preglednika za datoteke nad kojima nemate potpunu kontrolu: TopRow i LeftCol nisu ograničeni stvarno korišćenim opsegom radnog lista, pa klizač prevučen do strukturne granice može završiti na redu 1,048,576 ili koloni 16,384 i prikazati praznu mrežu umesto poslednjeg reda ili kolone koja zaista sadrži podatke; radne sveske dovoljno velike da to bude primetno obično su dovoljno velike i da zahtevaju pažnju pri učitavanju opisanu u članku o performansama velikih radnih svezaka
Povezivanje komentara i hiperveza sa događajima miša i izbora
TXLSWorkbookViewer tretira komentare i hiperveze kao atribute trenutno izabrane ćelije, a ne kao ciljeve pri prelasku mišem, pa se SelectedCellCommentText, SelectedCellCommentAuthor i SelectedCellHyperlink ažuriraju svaki put kada se aktivira OnSelectionChange, bez obzira na to da li je izbor pomeren klikom miša, tasterom sa strelicom ili pozivom GoToCell. Komentarisana ćelija dobija mali crveni trougao u gornjem desnom uglu kao vizuelni znak, slično Excelovoj oznaci komentara, ali taj marker je samo vizuelan; kontrolni element nema ugrađen opis koji se pokreće prelaskom miša, pa aplikacija koja želi iskačući prozor pri prelasku mišem umesto pri izboru mora sama da izgradi taj sloj. Aktiviranje hiperveze radi na isti način sa izborom kao prvim korakom: dvostruki klik na ćeliju poziva ActivateSelectedCell, koji čita SelectedCellHyperlink i, ako nije prazna, pokreće OnHyperlinkClick sa ciljnom adresom i parametrom var Handled: Boolean koji rukovalac treba da postavi
Jednako je važno šta OnHyperlinkClick ne radi: TXLSWorkbookViewer nikada ne poziva ShellExecute niti sam otvara pregledač, bez obzira na to da li rukovalac postavi Handled na true ili ga ostavi na false. Navigacija i svaka odluka o tome šta se smatra bezbednim ciljem u potpunosti su odgovornost aplikacije domaćina, što je ispravna podrazumevana postavka za komponentu koja ne može znati da li je ugrađena u pouzdani interni alat ili u preglednik datoteka koje je korisnik upravo otpremio
procedure TMainForm.ViewerSelectionChange(Sender: TObject; Row, Col: Integer);
begin
if Viewer.SelectedCellCommentText <> '' then
StatusBar.SimpleText := Viewer.SelectedCellCommentAuthor + ': ' +
Viewer.SelectedCellCommentText
else
StatusBar.SimpleText := Viewer.SelectedCellHyperlink;
end;
procedure TMainForm.ViewerHyperlinkClick(Sender: TObject;
const Target: WideString; var Handled: Boolean);
begin
ShellExecute(0, 'open', PWideChar(Target), nil, nil, SW_SHOWNORMAL);
Handled := True;
end;
Obim izbora i ograničenja navigacije tastaturom
Izbor u TXLSWorkbookViewer-u uvek je jedna logička ćelija, a prate ga SelectedRow i SelectedCol; osnovni kontrolni element nema pravougaoni izbor više ćelija, pa svaka funkcija koja treba da radi nad blokom ćelija mora biti izgrađena iznad njega, a ne pročitana iz objekta izbora. Podrška tastaturi je namerno osnovna: tasteri sa strelicama pomeraju se za jednu ćeliju, Home se vraća na početak reda ili, uz Ctrl, na ćeliju A1, Page Up i Page Down preskaču deset redova, a Tab i Shift+Tab prelaze preko kolona; ne postoji skok Ctrl+Arrow do ivice oblasti podataka niti izbor opsega proširen pomoću Shift, pa će korisnici koji dolaze direktno iz Excela primetiti taj nedostatak na gustom listu
Ograničenja kolona primenjuju se na istoj tački ChangeSelection koja obrađuje normalizaciju spajanja, a namerno se razlikuju po mehanizmu: preglednik povezan sa klasičnim TXLSWorkbook ograničava se na kolonu 256, strukturni maksimum formata BIFF8, dok preglednik povezan sa TXLSXWorkbook poštuje savremeno ograničenje od 16,384 kolona koje je XLSX nasledio od Excela 2007. Redovi su u oba slučaja ograničeni na 1,048,576, pa se praktična razlika između otvaranja stare XLS datoteke i XLSX datoteke u istom pregledniku u potpunosti svodi na to koliko udesno je mreža spremna da vas pusti
Ništa od ovoga nije neobično kada se razloži na pretragu piksela, normalizaciju sidra i nekoliko rukovalaca porukama, ali usklađivanje sva tri dela sa stvarnim datotekama, stvarnim spojenim ćelijama, komentarima i hipervezama predstavlja najveći deo posla u komponenti poput ove. TXLSWorkbookViewer isporučuje se kao deo standardne HotXLS Excel Component komponente za Delphi i C++Builder, zajedno sa klasičnim i XLSX objektnim modelima iz kojih prikazuje sadržaj