Vse, kar lebdi nad mrežo delovnega lista (grafikon, logotip, žig, oblaček z besedilom), je risalni objekt (drawing object), risalni objekt pa določata dve stvari: kaj je in kje je sidran. Sidro je tisti del, pri katerem se ljudje zmotijo. Grafikon ne živi v celici; nahaja se v pravokotniku, pripetem na določen razpon vrstic in stolpcev, podatki, ki jih izrisuje, pa so ločen nabor referenc A1, o katerih sidro ne ve ničesar. Premaknite okvir in grafikon bo ostal na mestu. Vstavite vrstice pod njim in okvir bo zdrsnil navzdol z njimi. Ohranjanje jasne ločnice med tema dvema koordinatnima sistemoma je večina tega, kar omogoča pravilno obnašanje risalne kode
HotXLS je izvorna knjižnica Object Pascal, ki bere in piše datoteke XLS in XLSX brez avtomatizacije Excela, in prinaša dva ločena risalna modela, saj formata datotek shranjujeta risbe različno. Format BIFF8 .xls ohranja grafikone na lastnih namenskih listih, lebdeče oblike pa v toku OfficeArt, ki je pripet delovnemu listu. Format OOXML .xlsx pa lahko vgradi grafikon neposredno v mrežo, sidranega na pravokotnik celic, skupaj z isto vrsto lebdečih slik in oblik. Predstavitev objektnega modela zrcali to razdelitev, napake, o katerih je vredno pisati, pa vse izhajajo iz uporabe pravil enega formata za drugega
Kateri vsebnik lahko vsebuje kaj
Izbira vsebnika mora priti pred kakršno koli kodo grafikona, saj se razpoložljivi tipi objektov med njima razlikujejo:
- XLS (BIFF8): grafikoni živijo na namenskih grafikonskih listih, ustvarjenih prek metode AddChartSheet v zbirki Sheets. Slike, polja z besedilom, pravokotniki, ovali in črte so oblike OfficeArt, ki se upravljajo prek zbirke Shapes delovnega lista. Ni API-ja za vgradnjo grafikona znotraj običajne mreže delovnega lista
- XLSX (OOXML): grafikone je mogoče vgraditi neposredno v delovni list z metodo TXLSXWorksheet.AddChart, sidrano na pravokotnik celic, ali postaviti na namenski grafikonski list s TXLSXWorkbook.AddChartSheet. Slike se dodajo z AddImage ali AddImageFromFile, lebdeče oznake pa z AddTextBox
Tako je zahteva, izražena kot "nadzorna plošča z grafikonom poleg številk", dejansko zahteva za .xlsx. V formatu .xls jo lahko le približate tako, da grafikon potisnete na lasten list, kar spremeni način, kako uporabnik krmari po datoteki, in spremeni obnašanje vaše kode. List, ki ga vrne metoda AddChartSheet na strani XLS, je podtok grafikona (chart substream) in ne mreža celic: pisanje nanj prek Cells.Item ustvari nekonsistenten risalni tok, ki se generira brez napak, Excel pa ga ob odpiranju nato zavrže. Grafikon preprosto izgine, v dnevniku gradnje pa nič ne pove, zakaj. Obravnavajte vrnjeni list kot izključno grafikonski in celoten razred poročil o "manjkajočem grafikonu" bo izginil
Vgradnja grafikona v delovni list XLSX
Pravokotnik sidra, posredovan metodi AddChart, je izražen v vrsticah in stolpcih delovnega lista ter določa, kje se nahaja okvir grafikona. Podatki serije so izraženi kot absolutne reference A1, ki vključujejo ime lista. Sta neodvisna: okvir lahko premaknete na drugi konec lista, pa bo še vedno izrisoval iste celice
var
Book: TXLSXWorkbook;
Sheet: TXLSXWorksheet;
Chart: TXLSXChart;
begin
Book := TXLSXWorkbook.Create;
try
Sheet := Book.Sheets.Add('Sales');
Sheet.Cells[1, 1].Value := 'Region';
Sheet.Cells[1, 2].Value := 'Revenue';
Sheet.Cells[2, 1].Value := 'East';
Sheet.Cells[2, 2].Value := 1184350;
Sheet.Cells[3, 1].Value := 'Central';
Sheet.Cells[3, 2].Value := 902210;
Sheet.Cells[4, 1].Value := 'West';
Sheet.Cells[4, 2].Value := 1010675;
// Frame anchored to rows 6..22, columns 1..8
Chart := Sheet.AddChart(xlsxChartColumn, 'Revenue by Region', 6, 1, 22, 8);
Chart.AddSeries('Revenue', 'Sales!$A$2:$A$4', 'Sales!$B$2:$B$4');
Chart.ValueAxisTitle := 'USD';
Sheet.AddImageFromFile(1, 5, 'logo.png');
Book.SaveAs('dashboard.xlsx');
finally
Book.Free;
end;
end;
Argument, ki povzroča težave, je niz območja, posredovan metodi AddSeries. Gre za dobesedni niz, zajet v trenutku klica, ki ne ve, da boste pozneje morda dodali še dvajset vrstic podatkov. Zgradite ga iz števila vrstic, ki ga izračunate po tem, ko so podatki že zapisani, nikoli prej. Raztreseni (scatter) in mehurčni (bubble) grafikoni preobremenijo ista dva argumenta z različnimi pomeni: območje kategorij zdaj ponuja vrednosti X, območje vrednosti pa Y, polmer mehurčkov pa prihaja iz tretje reference, nastavljene prek BubbleSizeRange na vrnjenem objektu TXLSXChartSeries. Klic berite kot "X, Y, velikost" in ne kot "kategorije, vrednosti", ko zapustite družino stolpčnih in vrstičnih grafikonov
Tip TXLSXChartType obsega stolpčne, vrstične, črtne, tortne, ploščinske, kolobarne, raztresene, mehurčne in radarske grafikone, kar pokriva vsakdanji nabor poročanja. Za celostranski grafikon brez okoliške mreže klic Book.AddChartSheet vrne list, katerega lastnost IsChartSheet je resnična. To je .xlsx različica starega grafikonskega lista in nosi enako pričakovanje: nanj ne pišite vsebine celic
Slike se vstavljajo kot bajti in so izmerjene v enotah EMU
Obstajata dve preobremenitvi za vstavljanje slike in njuno mešanje je hrošč, ki se najpogosteje pojavi pri pregledu kode. Klic AddImage(ARow, ACol, AData, AFormat) zahteva že kodirane bajte slike v AData: surovo vsebino PNG, JPEG, GIF ali BMP. Če mu posredujete pot do datoteke, boste shranili le štiridesetbajtni niz, ki ga noben pregledovalnik ne more dešifrirati, kar vodi v poročila o pokvarjeni sliki, ki jih po namestitvi ne želite razhroščevati. Če je vir datoteka na disku, raje pokličete AddImageFromFile in pustite, da knjižnica sama prebere bajte ter določi format
Nato sledi določanje velikosti. DrawingML ne meri v pikslih; meri v angleških metričnih enotah (English Metric Units - EMU), kjer 914400 enot EMU sestavlja palec, pri 96 DPI pa 9525 enot EMU predstavlja piksel. Objekt TXLSXImage izpostavlja lastnosti WidthEMU in HeightEMU, zato logotip, ki naj bi se izrisal v velikosti 180 krat 60 pikslov, potrebuje 1714500 krat 571500 enot EMU. To pretvorbo shranite v poimenovano konstanto in računajte z njo. Magične številke, kot je 1714500, raztresene po kodi, so nečitljive in napačne takoj, ko nekdo spremeni ciljni DPI. Sidrna vrstica in stolpec sta sicer 1-bazirana, kar ustreza preostalemu delu API-ja za celice in ne 0-bazirani matematiki EMU
Grafikonski listi in oblike v starejših datotekah XLS
Na strani BIFF8 bogatejša preobremenitev metode AddChartSheet sprejme tip grafikona, naslove osi in odprto polje zapisov TXLSChartSeriesInfo, kjer vsak zapis drži ime ter območji kategorij in vrednosti kot niza. Lebdeče oblike so ločena stvar: gredo na sam delovni list s podatki prek njegove zbirke Shapes in ne na grafikonski list
var
Book: IXLSWorkbook;
Data, Trend: IXLSWorksheet;
Series: array[0..0] of TXLSChartSeriesInfo;
begin
Book := TXLSWorkbook.Create; // interface-counted: do not Free
Data := Book.Sheets.Add;
Data.Name := 'Data';
Data.Cells.Item[1, 1].Value := 'Month';
Data.Cells.Item[1, 2].Value := 'Units';
Data.Cells.Item[2, 1].Value := 'Apr';
Data.Cells.Item[2, 2].Value := 1530;
Data.Cells.Item[3, 1].Value := 'May';
Data.Cells.Item[3, 2].Value := 1721;
Series[0].Name := 'Units';
Series[0].Categories := 'Data!$A$2:$A$3';
Series[0].Values := 'Data!$B$2:$B$3';
Trend := Book.Sheets.AddChartSheet('Trend', xlsChartTypeLine,
'Units sold', 'Month', 'Units', Series);
// Trend is a chart substream: never call cell methods on it
Data.Shapes.AddTextBox('Source: ERP nightly export', 6, 1, 8, 4);
Data.Shapes.AddPicture('approved-stamp.bmp');
Book.SaveAs('trend.xls');
end;
Tukaj sta pomembni dve podrobnosti o življenjskem ciklu, ki vlečeta v nasprotni smeri. TXLSWorkbook se drži prek vmesnika IXLSWorkbook in je referenčno šteti, zato klic metode Free sproži dvojno sprostitev pomnilnika. TXLSXWorkbook iz prejšnjih razdelkov pa je navaden objekt in ga je treba sprostiti znotraj bloka try..finally. Isti pregledovalnik kode, ki opozori na manjkajoči Free na strani XLSX, mora opozoriti na prisotnost tega na strani XLS, kar predstavlja resno nevarnost za napake, ko delate z obema formatoma v isti enoti. Pomožniki za oblike so enotni: AddRectangle, AddOval in AddLine z metodo DeleteInRange za čiščenje območja risb se vsi sidrajo prek parov vrstic in stolpcev, tako da jih predloga, ki nad njimi vstavi vrstice, premakne skupaj z mrežo
Še ena lastnost se obrestuje na starejših datotekah. TXLSPicture.TransparentColor maskira izbrano barvo ozadja iz bitne slike, kar vam omogoča, da postavite nepravokoten žig (pečat "Approved", vodni znak) čez mrežo v formatu, katerega upodabljanje BIFF se nikoli ni naučilo prosojnosti PNG alfa. Nastavite barvo, s katero je bil žig ustvarjen, in okoliški pravokotnik bo izginil
Sistemske barve (Theme colors) ne preživijo povratne poti BIFF8
Polnila risb OOXML lahko kažejo na režo sistemske barve (theme color slot), zato je spreminjanje barv celotnega delovnega zvezka .xlsx s preprosto zamenjavo teme poceni. Risalni zapisi BIFF8 nimajo takšne reže. Ko HotXLS uporabi sistemsko barvo na risbi XLS, barvo razreši v dejansko vrednost RGB in jo shrani; indeks teme, iz katere izhaja, izgine takoj, ko je datoteka zapisana, ponovno odpiranje pa ga ne more obnoviti. To vpliva predvsem na orodja za poročanje pod lastno blagovno znamko (white-label), ki morajo isto ustvarjeno poročilo prilagoditi za različne stranke. Preslikavo iz teme v RGB ohranite v lastni konfiguraciji in jo znova uporabite ob vsakem generiranju, namesto da bi jo pričakovali prebrati iz shranjene datoteke .xls
Strani XLS je mogoče naročiti, naj v celoti preskoči razčlenjevanje risalne plasti, ko želite iz velike starejše datoteke pridobiti le podatke o celicah, in sicer z nastavitvijo _DisableGraphics na true, kar znatno skrajša čas množičnega branja. Zanka pa je trajna: delovni zvezek, odprt na ta način, nima toka OfficeArt v pomnilniku, zato njegovo shranjevanje izbriše risbe. Zastavico rezervirajte izključno za analitična opravila, ki so namenjena le branju. Širša slika zmogljivosti je v naših zapiskih o zmogljivosti velikih delovnih zvezkov v HotXLS
Ohranjanje stabilnosti sider med spreminjanjem mreže
Poročila le redko ostanejo enake velikosti, kot so bila ustvarjena, in tu se obrestuje model sidranja iz uvoda. Strukturne operacije na strani XLSX (InsertRows, DeleteRows in stolpčne ustreznice) premikajo odvisne plasti skupaj s celicami. Združena območja, hiperpovezave, komentarje, zamrznjena polja, obsegi filtrov, pogojni formati, validacije, tabele, definirana imena ter, za to temo, sidra slik in grafikonov potujejo skupaj. Logotip, sidran v 1. vrstici, ostane na vrhu, ko pod njim vstavite deset vrstic. Okvir grafikona, sidran pod podatkovnim blokom, zdrsne navzdol, ko blok raste. Edina stvar, ki se ne prepiše, pa je kateri koli niz območja, ki ste ga zajeli kot dobesedni niz pred vstavljanjem, saj je to le besedilo, ki ga knjižnica nima razloga ponovno obiskati. To določa varen vrstni red za zapolnjevanje predlog: najprej zapišite in oblikujte podatke, ustvarjanje grafikonov in postavitev slik pa izvedite kot zadnji korak, pri čemer vsak niz območja izpeljite iz števila vrstic, ki jih imate po vstavljanju in ne pred njim
Dve manjši orodji dopolnjujeta nabor za postavitev. Metoda TXLSTextBox.SetArea na strani XLS znova zasidra obstoječe polje z besedilom ali samodejno obliko na nov pravokotnik celic, kar je boljše od brisanja in ponovnega ustvarjanja, ko se blok noge (footer) premakne. In preobremenitev AddPicture za bitne slike sprejme živi TBitmap z neobvezno zastavico prosojnosti, tako da se lahko vse, kar lahko nariše vaša lastna koda VCL (merilnik, trak mini grafikonov ali tip grafikona, ki ga privzeti seznam ne ponuja), vtisne neposredno na list, ne da bi morali najprej zapisati začasno datoteko
Grafikoni in slike so skoraj vedno končni sloj na že strukturiranem poročilu, zato osnova določa, ali bodo pristali na pravem mestu. Polnjenje podatkov, na katere se bo nanašal grafikon, obravnava članek o ustvarjanju poročil na podlagi predlog, ohranjanje stabilnosti mreže pod vašimi sidri pa je tema članka o združenih celicah in nadzoru postavitve. Celotna dokumentacija razredov in metod se nahaja na strani izdelka HotXLS Component