HotXLS toimittaa TXLSWorkbookViewer-luokan, natiivin VCL-ohjausobjektin, joka renderöi XLS-, XLSX-, XLSM- ja ODS-työkirjat interaktiivisena laskentataulukkoruudukkona Delphi- tai C++Builder-lomakkeen sisällä, asentamatta Exceliä tai ohjaamatta sitä OLE-automaation kautta. Tällaisen ohjausobjektin rakentaminen hyvin tarkoittaa kolmen tarkan ongelman ratkaisemista: hiiren klikkauksen, joka osuu yhdistetyn solun sisään, kartoittaminen oikeaan loogiseen soluun, vieritysaseman, otsikkokaistojen ja solunvalinnan pitäminen johdonmukaisena, kun käyttäjä panoroi arkkia, joka on paljon näkyvää ikkunaa suurempi, ja päättäminen, mitä klikkaus kommenttimerkinnällä tai hyperlinkkisolulla todella pitäisi tehdä
Useimmat Delphi-yritykset tavoittelevat laskentataulukon katseluohjelmaa syistä, jotka eivät liity muokkaamiseen: tarkastusasema, joka esikatselee ladattuja työkirjoja ennen kuin ne pääsevät putkeen, kioski tai raporttikatselin, jossa Microsoft Office ei ole osa käyttöönottokuvaa, tai QA-työkalu, joka tarvitsee näyttää työkirjan sisällön ilman todellisen Excel-prosessin COM:in yli automatisoinnin ennalta-arvaamattomuutta. Tavallinen merkkijonoruudukko antaa sinulle tekstiä soluihin nopeasti, mutta laskentataulukkotiedosto ei ole tavallinen ruudukko: solut yhdistyvät lohkoiksi, jotka ovat olemassa vain kerran taustalla olevassa mallissa, arkit kantavat kiinteitä otsikkokaistoja ja itsenäisiä vaaka- ja pystyvierityssijainteja, ja yksittäiset solut kantavat kommentteja ja hyperlinkkejä, jotka tarvitsevat oman vuorovaikutusmallinsa. TXLSWorkbookViewer on HotXLS:n vastaus tähän aukkoon, ja sen sisäinen suunnittelu on järkevä pohjapiirustus kenelle tahansa, joka rakentaa vastaavaa ohjausobjektia alusta
Miten työkirjan katseluohjelma välttää riippuvuuden Excelistä?
TXLSWorkbookViewer välttää Excelin kokonaan lukemalla HotXLS:n oman jäsennellyn olio-mallin kautta sen sijaan, että avaisi asiakirjan Excelin kautta ja ohjaisi sitä nukketeatterina. Workbook-ominaisuus sitoo olemassa olevan TXLSWorkbook-olion klassisille XLS-tiedostoille, ja XlsxWorkbook sitoo TXLSXWorkbook-olion XLSX-, XLSM- ja mallimuunnoksille; kumpi tahansa voi olla jo auki muualla sovelluksessa, ja katseluohjelma vain lukee siitä. Kun ohjausobjektin pitäisi omistaa tiedosto itse, LoadFromFile tarkastaa päätteen, ohjaa XLSX-, XLSM-, XLTX-, XLTM- ja ODS-tiedostot modernin moottorin kautta ja kaiken muun klassisen moottorin kautta, ja vapauttaa kumman tahansa työkirjan, jonka se loi, heti kun ohjausobjekti tyhjennetään tai tuhotaan
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;
Oikean solun paikantaminen yhdistetyn alueen sisältä
Klikkauksen ratkaiseminen oikeaan soluun TXLSWorkbookViewer:ssä on kaksivaiheinen haku, ja jako on merkityksellinen, koska pikseligeometria ja laskentataulukkosemantiikka ovat aidosti erilaisia ongelmia. Ensimmäinen vaihe on puhdasta geometriaa: yksityinen CellAtPoint-metodi käy läpi sarakeleveydet ja rivikorkeudet nykyisestä vierityssijainnista, kunnes se löytää kaistan, joka sisältää klikatun X- ja Y-koordinaatin, ilman minkäänlaista tietoisuutta yhdistetyistä soluista. Toinen vaihe on semanttinen: jokainen polku, joka muuttaa valintaa, hiiriklikkaus, nuolinäppäin, Tab tai suora kutsu funktioon GoToCell, ohjautuu yhden sisäisen ChangeSelection-rutiinin kautta, joka normalisoi raa'an rivin ja sarakkeen minkä tahansa yhdistelmän suhteen ja napsauttaa ne yhdistelmän ankkurisoluun ennen kuin valinta todella muuttuu
Ankkuri on yhdistetyn alueen vasen yläkulmasolu, ja se on ainoa solu tuossa lohkossa, joka aidosti kantaa arvon, muodon, kommentin tai hyperlinkin taustalla olevassa työkirjamallissa; jokainen muu solu, jonka yhdistelmä visuaalisesti kattaa, on tyhjä itse datassa. Klassisille XLS-työkirjoille ankkuri tulee kentästä Cell.MergeArea, IXLSRange-oliosta, jonka Row ja Column osoittavat omistavaan soluun; XLSX- ja ODS-työkirjoille MergedCells.FindAt palauttaa TXLSXMergedRange-olion, joka paljastaa saman ankkurin Row1- ja Col1-kenttinä. Piirto ratkaisee vastaavan ongelman itsenäisesti, laajentaen yhdistetyn solun suorakulmion sen täyteen rivi- ja sarakekattavuuteen ja ohittaen tuon kattavuuden sisällä olevat solut, joten valinnan ääriviiva kääriytyy koko yhdistetyn lohkon ympärille eikä vain sen ankkurikulman, ja yhdistettyjen asettelujen kirjoittaminen niiden pelkän takaisinlukemisen sijaan on liittyvä mutta erillinen ongelma, joka käsitellään rinnakkaisartikkelissa yhdistettyjen solujen asettelu raporttimalleille
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;
Mikä pitää vierityksen, otsikot ja valinnan synkronoituna?
TXLSWorkbookViewer pitää kolme erillistä tilan osaa yhtenäisenä: loogisen vierityssijainnin, joka on kentissä TopRow ja LeftCol, natiivit Windows-vierityspalkit, joita ohjausobjekti pyytää WS_HSCROLL- ja WS_VSCROLL-lipuilla funktiossa CreateParams, ja nykyisen valinnan kentissä SelectedRow ja SelectedCol. Vierityspalkin vetäminen tai hiiren rullan pyörittäminen laukaisee WM_HSCROLL-, WM_VSCROLL- tai WM_MOUSEWHEEL-viestin, joka päivittää TopRow- tai LeftCol-arvon ja piirtää uudelleen; valinta ei liiku, mikä vastaa sitä, miten Excel itse erottaa panoroinnin valinnasta. Minkä tahansa noista päivityksistä jälkeen UpdateScrollBars työntää uuden sijainnin takaisin natiiviin vierityspalkkiin SetScrollInfo-funktion kautta, joten kahva ei koskaan ajaudu erimielisyyteen siitä, mitä ruudukko todella näyttää
Näppäimistönavigointi ajaa saman synkronoinnin vastakkaiseen suuntaan: valinnan siirtäminen näkyvän ruudukon reunan ohi kutsuu EnsureSelectionVisible-metodia, joka nykii TopRow- tai LeftCol-arvoa kertymällä todellisia sarakeleveyksiä ja rivikorkeuksia yksinkertaisen yhdellä kasvattamisen sijaan, koska rivit ja sarakkeet voivat kantaa mukautettuja kokoja, ja kutsuu sitten UpdateScrollBars-funktiota, jotta kahva heijastaa sitä, minne näppäimistö juuri vei näkymän. Rivinumero- ja sarakekirjainotsikkokaistat, kooltaan asetettuina RowHeaderWidth- ja ColumnHeaderHeight-kenttien kautta, ovat se osa tätä ohjausobjektia, joka pysyy kiinteänä näytöllä, kun TopRow ja LeftCol vierittävät alla olevaa dataa, ja se on koko laajuus jäädyttämisestä, jonka tämä ohjausobjekti tekee itsenäisesti: se ei ole Excelin Freeze Panes -ominaisuus, eikä ole sisäänrakennettua tapaa kiinnittää mielivaltaista datariviä tai -saraketta samalla, kun arkin loppuosa vierii sen ohi. Yksi raja, joka kannattaa testata ennen katseluohjelman toimittamista tiedostoille, joita et täysin hallitse, on se, että TopRow ja LeftCol eivät ole rajattuja työarkin todellista käytettyä aluetta vasten, joten rakenteelliseen rajaansa vedetty kahva voi osua riville 1 048 576 tai sarakkeeseen 16 384 ja näyttää tyhjän ruudukon viimeisen datan sisältävän rivin tai sarakkeen sijaan; työkirjat, jotka ovat tarpeeksi suuria tehdäkseen tämän huomattavaksi, ovat yleensä myös tarpeeksi suuria tarvitakseen huomion, joka käsitellään artikkelissa suurten työkirjojen suorituskyky
Kommenttien ja hyperlinkkien kytkeminen hiiri- ja valintatapahtumiin
TXLSWorkbookViewer kohtelee kommentteja ja hyperlinkkejä minkä tahansa nykyisin valitun solun attribuutteina eikä hover-kohteina, joten SelectedCellCommentText, SelectedCellCommentAuthor ja SelectedCellHyperlink päivittyvät joka kerta, kun OnSelectionChange laukeaa, liikkuipa valinta hiiriklikkauksella, nuolinäppäimellä tai GoToCell-kutsulla. Kommentoitu solu saa pienen punaisen kolmion piirrettynä oikeaan yläkulmaansa visuaalisena vihjeenä, samankaltaisena kuin Excelin oma kommenttilippu, mutta tuo merkki on puhtaasti visuaalinen; ohjausobjektiin ei ole rakennettu hover-laukaisemaa työkaluvihjettä, joten sovelluksen, joka haluaa ponnahdusikkunan hiiren päällä valinnan sijaan, on rakennettava tuo kerros itse. Hyperlinkin aktivointi toimii samalla valinta-ensin-tavalla: solun kaksoisklikkaus kutsuu ActivateSelectedCell-metodia, joka lukee SelectedCellHyperlink-kentän, ja jos se ei ole tyhjä, nostaa OnHyperlinkClick-tapahtuman kohdeosoitteella ja var Handled: Boolean-parametrilla käsittelijän asetettavaksi
Se, mitä OnHyperlinkClick ei tee, on yhtä tärkeää: TXLSWorkbookViewer ei koskaan kutsu ShellExecute-funktiota tai avaa selainta itsenäisesti, riippumatta siitä, asettaako käsittelijä Handled-arvon todeksi vai jättääkö sen epätodeksi. Navigointi, ja mikä tahansa päätös siitä, mikä lasketaan turvalliseksi kohteeksi, on kokonaan isäntäsovelluksen vastuulla, mikä on oikea oletus komponentille, jolla ei ole aavistustakaan siitä, onko se upotettuna luotettuun sisäiseen työkaluun vai katseluohjelmaan tiedostoille, jotka asiakas juuri latasi
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;
Valinnan laajuus ja näppäimistönavigoinnin rajat
Valinta TXLSWorkbookViewer:ssä on aina yksi looginen solu, seurattuna kentissä SelectedRow ja SelectedCol; perusohjausobjektissa ei ole suorakulmaista monisoluvalintaa, joten mikä tahansa ominaisuus, joka tarvitsee toimia solulohkolla, on rakennettava sen päälle sen sijaan, että se luettaisiin valintaoliosta. Näppäimistökattavuus on tarkoituksella perustavanlaatuinen: nuolinäppäimet siirtävät yhden solun kerrallaan, Home palaa rivin alkuun tai, Ctrl:n kanssa, soluun A1, Page Up ja Page Down hyppäävät kymmenen riviä, ja Tab sekä Shift+Tab askeltavat sarakkeiden yli; Ctrl+nuoli-hyppyä datan alueen reunaan ei ole, eikä Shift-laajennettua aluevalintaa, joten Excelistä suoraan tulevat käyttäjät huomaavat aukon tiheällä arkilla
Sarakerajat pakotetaan samassa ChangeSelection-pullonkaulassa, joka käsittelee yhdistelmän normalisoinnin, ja ne eroavat moottorin mukaan tarkoituksella: klassiseen TXLSWorkbook-olioon sidottu katseluohjelma rajaa sarakkeeseen 256, BIFF8-muodon rakenteellisen katon, kun taas TXLSXWorkbook-olioon sidottu kunnioittaa modernia 16 384 sarakkeen rajaa, jonka XLSX peri Excel 2007:stä eteenpäin. Rivit on rajattu 1 048 576:een kummassakin tapauksessa, joten käytännön ero vanhan XLS-tiedoston ja XLSX-tiedoston avaamisen välillä samassa katseluohjelmassa liittyy kokonaan siihen, kuinka pitkälle oikealle ruudukko sallii sinun mennä
Mikään tästä ei ole eksoottista, kun se on hajotettu pikselihauksi, ankkurin normalisoinniksi ja kourallliseksi viestinkäsittelijöitä, mutta näiden kolmen saaminen sopusointuun todellisten tiedostojen, todellisten yhdistelmien, kommenttien ja hyperlinkkien alla on suurin osa työstä tällaisessa komponentissa. TXLSWorkbookViewer toimitetaan osana vakiomuotoista HotXLS Excel -komponenttia Delphille ja C++Builderille, yhdessä klassisten ja XLSX-olio-mallien kanssa, joista se renderöi