Műszaki cikk

Diagramobjektumok beágyazása munkalapokra a HotXLS-ben

A HotXLS a diagramot közvetlenül a munkalapra helyezheti, cellatartományhoz rögzítve, ahelyett hogy dedikált diagramlapra tenné. BIFF8 szóhasználattal ez azt jelenti, hogy rajzolási alakzatot ír OBJ típus-5 rekorddal, és a diagram substreamet a munkalap rekordfolyamának végére parkolja, ami pontosan az az elrendezés, amelyet az Excel előállít, és pontosan ott, ahol az olvasó megtalálja

A megkülönböztetés mindenkinek fontos, aki éles jelentéseket gyárt. Egy diagramlap remek otthon egyetlen címsor-vizuálnak. Egy havi regionális bontás azt akarja, hogy a diagram a számok mellett legyen, amelyeket összegz, ugyanazon a lapon, ahhoz a cellablokkhoz méretezve, amelyhez tartozik, tehát az olvasó egyszer görget ahelyett, hogy lapfüleket váltana, és elveszítené a kontextust

Az olvasás már megvolt, az írás nem

Az aszimmetriát érdemes megnevezni, mert formálja a munkát. A HotXLS már tudott beágyazott diagramokat olvasni: amikor a munkalap rekordfolyama BOF-ot tartalmaz, amely diagram substreamként van jelölve, az elemző kontextust vált, összegyűjti a diagramrekordokat, és a záró EOF-nál visszaadja őket annak a rajzolási alakzatnak, amelyet az OBJ rekord bevezetett. Ezt az utat a könyvtár által valaha megnyitott minden Excel által gyártott munkafüzet gyakorolta

Ami hiányzott, az a szerkesztési oldal volt, és a hasznos következmény az, hogy az új írónak volt egy pontos előírás, amelyet el kell találnia: előállítani azt a bájt-elrendezést, amelyet a meglévő olvasó már vissza tud fűzni. Nincs jobb elfogadási kritérium egy bináris formátum funkciójára, mint egy önállóan írt olvasó, amelyet nem módosíthatott

Miből áll egy beágyazott diagram?

Három darabnak kell egyetértenie. A rajzolási réteg egy gazdavezérlő alakzatot ad, az objektumréteg egy OBJ rekordot ad, amelynek közös objektumadata az 5-ös objektumtípust deklarálja, a rekordfolyam pedig magát a diagram substreamet. Az OBJ rekord opciózászlói azok, amelyeket az Excel egy diagramkerethez ír: positioned, locked, automatic line és automatic fill, és ez az, ami miatt a beágyazott diagram natívként viselkedik, amikor egy felhasználó rákattint

A HotXLS három egyetértő darabon keresztül rögzít BIFF8 diagram substreamet Delphi munkalaphoz: a rajzolási réteg gazdavezérlő alakzata, az OBJ rekord, amelynek közös objektumadata az 5-ös objektumtípust deklarálja, és a munkalap rekordfolyamának végére parkolt diagramrekord-lánc, ahol egy diagram BOF kontextust vált az elemzőben, és a záró EOF visszafűzi a rekordokat
Három réteg hordoz egy beágyazott diagramot: a rajzolási alakzat rögzíti, az OBJ rekord diagramgazdaként típusozza, és a lapfolyam végén lévő diagram substream szolgáltatja a rekordokat, amelyeket az olvasó visszafűz

A rögzítés megérdemel egy megjegyzést, mert az off-by-one hibák gyakori forrása. A HotXLS API egy alapú sor- és oszlopszámokat fogad, a könyvtár többi részéhez igazodva, a fájlba írt client anchor viszont nulla alapú. Az átváltás a AddChartObject-on belül történik, tehát a hívók abban a koordinátarendszerben maradnak, amelyet mindenhol máshol használnak, de aki hex dumpot vet össze a saját hívásával, annak emlékeznie kell, hogy a határ melyik oldalát olvassa

var
  Book: TXLSWorkbook;
  Sheet: TXLSWorksheet;
  Series: array[0..1] of TXLSChartSeriesInfo;
begin
  Book := TXLSWorkbook.Create(nil);
  try
    Book.LoadFromFile('regional-sales.xls');
    Sheet := Book.Sheets[0];

    FillChar(Series, SizeOf(Series), 0);
    Series[0].Name := 'Actual';
    Series[0].Categories := 'Data!$A$2:$A$13';
    Series[0].Values := 'Data!$B$2:$B$13';
    Series[0].DataLabels.ShowValue := True;
    Series[0].HasDataLabels := True;

    Series[1].Name := 'Target';
    Series[1].Categories := 'Data!$A$2:$A$13';
    Series[1].Values := 'Data!$C$2:$C$13';
    Series[1].SecondaryAxis := True;

    // Erre a lapra rögzítve E2:M20 tartományhoz, egy alapú
    Sheet.AddChartObject(xlsChartTypeColumn, 'Regional sales',
      'Month', 'Amount', Series, 2, 5, 20, 13);

    Book.SaveToFile('regional-sales-charted.xls');
  finally
    Book.Free;
  end;
end;

A FillChar a sorozattömbön nem dekoráció. A TXLSChartSeriesInfo több opcionális alrekordot hordoz, adatcímkéket, sorozatonkénti stílust, trendvonalakat és hibasávokat, mindegyiket boolean őrzi, és egy részben inicializált rekord a stacken olyan zászlókat ad az emitternek, amelyeket senki nem állított. Nullázza a tömböt, aztán állítsa be azokat a mezőket, amelyeket gondol

Milyen sorozathivatkozásokat fogad el a beágyazott út?

Sima A1-stílusú tartományok ugyanabban a munkafüzetben, és ez a korlátozás szándékos, nem áttekintési hiba. Minden hivatkozás a munkafüzet laplistáján oldódik fel, és a diagramrekordok által igényelt külső hivatkozási indexszé alakul. Egy nevesített tartomány vagy külső munkafüzet-hivatkozás nulla hosszúságú elemzett kifejezésű helyőrzőre esik vissza, tehát a diagram tisztán íródik, de az adott sorozatnak nincs adatforrása, amíg tartományra nem mutat

HotXLS sorozathivatkozás-elfogadás a beágyazott BIFF8 diagram úton: az A1-stílusú tartományok, mint a Data!$B$2:$B$13, ugyanabban a munkafüzetben a laplistán oldódnak fel a diagramrekordok által igényelt külső hivatkozási indexszé, míg a nevesített tartományok és a külső munkafüzet-hivatkozások nulla hosszúságú elemzett kifejezésű helyőrzőre esnek vissza, mindkettőt az AddChartSheet fedi
Csak a sima A1-stílusú tartományok fordulnak diagramsorozat-hivatkozásokká ugyanabban a munkafüzetben; minden más tisztán íródik helyőrzőként átirányításig, a teljes út pedig az AddChartSheeten él

Az ok egyenes mérnöki kompromisszum. A teljes hivatkozásfordítási út a diagramlap úton létezik, a munkalapgyűjtemény rétegébe csomagolva, és tisztán kiemelni azt száz sor feloldási logika megkettőzését jelentené egy olyan esetért, amely a gyakorlatban ritka. Egy beágyazott diagram szinte mindig a saját lapján vagy egy testvér adatlapon lévő cellákat ábrázol. A nevesített és külső hivatkozások a diagramlap úton érhetők el az AddChartSheet-en keresztül, tehát semmi sem elérhetetlen, csak egy másik belépési pontról közelíthető meg

A sorozatmodell minden mása azonos módon működik mindkét úton. A másodlagos tengelykötés, a sorozatonkénti vonal-, kitöltés- és jelölőstílusok, a trendvonalak, a hibasávok és az adatcímkék mind a TXLSChartSeriesInfo részei, és ugyanúgy emitálódnak, tehát egy diagramdefiníció mozoghat beágyazott objektum és diagramlap között, csak a hívás változik. A másodlagos tengely zászlója mögötti tengelycsoport-mechanikát a másodlagos tengelycsoportok BIFF íráskor tárgyalja

Miért olvasódott a diagramcím két karakterként?

Mert karakteres darabszámot adtak át ott, ahol bájt darabszámot vártak, és a BIFF Unicode sztringek miatt ezt a hibát könnyű elkövetni és nehéz látni. Egy rövid BIFF Unicode sztring karakteres darabszámmal és zászlóbájttal kezdődik, és a zászlóbájt viseli a high-byte bitet, amely megmondja, hogy a hasznos adat egy vagy két bájt karakterenként. Olvasson egy 16 bites hasznos adatot a karakterdarabszámmal, mintha bájt hossz volna, és pontosan a sztring felét kapja: egy Sales nevű sorozat Sa-ként tér vissza, és egy diagramcím ugyanígy csonkolódik, mert a címek és a sorozatcímkék osztoznak a dekódolási úton

Amit a hiba említésre méltóvá tesz, az, hogy háromszor ismétlődött meg ugyanazon rekordcsaládban, egyszer a trendvonalnevekben, egyszer a pivot diagramnevekben, egyszer pedig a diagramcímekben. Minden előfordulás friss hibának látszott egy új funkcióban. Mindhárom ugyanaz volt: a hiányzó szorzás. Az a szabály, amely végül lezárta, mechanikus, és megítélés nélkül kell alkalmazni: amikor e sztringek egyikét olvassa, először nézze meg a high-byte zászlót, és szorozza meg a karakterdarabszámot a hasznos adat szélességével, mielőtt a bufferhez nyúlna. A rekordszintű részletek a XLUnicodeString karakterdarabszámok és a high-byte zászló dekódolása cikkben vannak

// A beágyazott diagram a rajzolási réteget osztja a képekkel és
// alakzatokkal, tehát a lapon lévő meglévő rajz megmarad. Az
// AddChartObject a létrehozott objektum indexét adja vissza
var
  ObjIndex: Integer;
begin
  ObjIndex := Sheet.AddChartObject(xlsChartTypeLine, 'Trend',
    'Week', 'Units', Series, 2, 8, 18, 16);
  if ObjIndex < 0 then
    raise Exception.Create('chart object was not created');
end;

Hol férnek el a beágyazott diagramok az alternatívákhoz képest

Három út létezik, és különböző kérdésekre válaszolnak. Egy beágyazott diagramobjektum az adatai mellé való a munkalapon, és ez az, amit a legtöbb jelentés akar. Egy diagramlap egyetlen bemutatóvizuálhoz illik, és megadja a teljes hivatkozásfordítási utat. Egy betöltött fájlból származó meglévő diagram érintetlen megtartása akkor a helyes válasz, amikor a munkafüzet Excelből jött olyan formázással, amelyet senki sem akar, hogy a könyvtár újraértelmezen; az átengedő viselkedést a megőrzött ChartML és kombinált diagramok írja le

Mivel a beágyazott diagram a rajzolási rétegen utazik, együtt él a képekkel és alakzatokkal ugyanazon a lapon, ahelyett hogy kiváltaná őket, és annak a rétegnek az általános modelljét a diagramok, képek és rajzok a HotXLS-ben tárgyalja. Mindhárom út szállul a HotXLS Delphi táblázatkezelő komponensben, tehát a választás arról szól, hogyan kell kinéznie a jelentésnek, nem arról, mit tud kifejezni a könyvtár

A metodológiai pont az, amelyet érdemes megtartani. Amikor egy bináris formátum funkciójának már van meglévő olvasója, az írót az olvasóhoz építse, nem a specifikáció saját olvasatához. Az olvasó éveknyi érintkezést testesít meg azokkal a fájlokkal, amelyeket valós alkalmazások ténylegesen gyártottak, ideértve azokat a részeket is, amelyeket a specifikáció lazán mond ki, és az az író, amely ezt kielégíti, jóval valószínűbben elégíti ki az Excelt is