Teknisk artikel

Excel-kameraobjekter fra Delphi: Levende øjebliksbilleder

HotXLS opretter Excel-kameraobjekter på XLSX-regneark fra Delphi via AddCamera. Et kameraobjekt er et billede, der er permanent knyttet til et celleområde: Excel gengiver det på ny fra kildeområdet, hver gang projektmappen åbnes, eller kilden ændres, så et dashboard kan vise en levende visning af en tabel, der ligger på et andet ark, i enhver størrelse, roteret hvis du ønsker det

Funktionen findes i Excel som Kamera-værktøjet, en knap de fleste brugere aldrig har set, fordi den ikke er på båndet som standard. Den løser et reelt dashboard-problem bedre end alternativerne: et kopieret område bliver forældet, et diagram kan ikke vise vilkårligt celleindhold, og et linket billede indsat manuelt kan ikke genereres af kode. Et kameraobjekt er den ene konstruktion, der er både levende og vilkårlig

HotXLS-kameraobjekt oprettet fra Delphi: et levende billede af Data!$B$2:$D$4 placeret på et dashboard-ark, som Excel gengiver på ny ved åbning og ved hver kildeændring
Et kameraobjekt forbliver permanent knyttet til sit kildeområde, så Excel gengiver billedet på ny ved åbning og ved hver redigering, i enhver størrelse og fra et område på et andet ark

Hvor er dette dokumenteret, og hvorfor betyder det noget?

Hovedspecifikationen for regneark beskriver ikke kameraobjekter; de behandles som en implementeringsdetalje. Den autoritative beskrivelse findes i dokumentationen for tegnings-markup, under overskriften Camera Tool, og at vide det sparer en eftermiddags søgning i det forkerte dokument

Strukturelt er et kameraobjekt et almindeligt billedelement, hvis ikke-visuelle billedegenskaber bærer en udvidelsesliste. Udvidelsen identificeres af en fast GUID, og inde i den registrerer et element fra 2010-tegnings-namespacet to ting: kildeområdet som en absolut A1-stil-reference, valgfrit arkkvalificeret, og en formidentifikator. Alt andet ved billedet er normalt

XLSX-anatomi af et kameraobjekt skrevet af HotXLS fra Delphi: et almindeligt billedelement, hvis udvidelsesliste bærer et element fra 2010-tegnings-namespacet, der registrerer det absolutte kildeområde og en formidentifikator
Strukturelt er et kamera et almindeligt billede plus ét udvidelseselement fra 2010-tegnings-namespacet, der registrerer det absolutte A1-stil-kildeområde og en formidentifikator

Sådan opretter du ét

Der findes to overloads, fordi to måder at navngive et område er praktiske. Tekstformen tager referencen præcis, som den vil blive gemt, hvilket er det, du vil have til en tvær-ark-kilde. Koordinatformen tager fire cellekoordinater på det samme ark og bygger den absolutte reference for dig:

uses
  lxHandleX;

var
  Book: TXLSXWorkbook;
  Dashboard: TXLSXWorksheet;
  Cam: TXLSXImage;
begin
  Book := TXLSXWorkbook.Create;
  try
    if Book.Open('reporting.xlsx') <> 1 then
      Exit;
    Dashboard := Book.Sheets[0];

    // Levende visning af Data!$B$2:$D$4, placeret over B10:F20 på dashboardet
    Cam := Dashboard.AddCamera('Data!$B$2:$D$4', 10, 2, 20, 6);

    // Placeringsboksen bruger som standard Excels egne 64 px-kolonner og
    // 20 px-rækker; justér den tegnede størrelse i EMU bagefter, hvis nødvendigt
    Cam.WidthEMU := Round(12.5 * 914400 / 2.54);   // 12,5 cm
    Cam.HeightEMU := Round(6.0 * 914400 / 2.54);

    Book.SaveAs('reporting-dashboard.xlsx');
  finally
    Book.Free;
  end;
end;

Det returnerede objekt er et normalt billedobjekt med én ekstra egenskab, CameraRange, som er ikke-tom netop når billedet er et kamera. Det er også sådan, du opdager kameraer i en projektmappe, du ikke selv har oprettet: opremse billederne, og tjek egenskaben

Hvorfor behøver placeholder-billedet ikke være ægte?

Hvert billede i en XLSX-pakke har brug for en billeddel, og et kameraobjekt er ingen undtagelse. Men Excel ignorerer det billede: ved indlæsning gengiver det det linkede område på ny og tegner resultatet. De indlejrede bytes eksisterer udelukkende som en visningscache til værktøjer, der ikke implementerer kamera-adfærden

Den kendsgerning fjerner et helt undersystem fra implementeringen. Der er intet behov for at rasterisere kildeområdet, intet behov for en gengivelsesmotor til at producere øjebliksbilledet, og ingen risiko for, at det cachede billede er uenig med det levende i Excel. HotXLS skriver en minimal placeholder-metafil — en header-post og en end-of-file-post, 108 bytes i alt — hvilket holder pakken strukturelt komplet og koster intet

Én konsekvens at planlægge for: en fremviser, der gengiver XLSX uden at implementere kameraobjekter, viser placeholderen, som er blank. Hvis dine projektmapper forbruges af et sådant værktøj, er et kameraobjekt den forkerte konstruktion, og et gengivet billede af området er den rigtige

Placeholder-billeddel af et HotXLS-kameraobjekt: Excel gengiver det linkede område på ny ved indlæsning og ignorerer den 108-byte metafil, mens fremvisere uden kamerastøtte viser et blankt billede
Excel ignorerer de indlejrede bytes og gengiver det linkede område på ny ved indlæsning, så HotXLS kun skriver en 108-byte placeholder-metafil, mens en fremviser uden kamerastøtte viser den blanke placeholder

Enhedskonverteringen, det er let at tage fejl af

Tegnegeometri i Open XML måles i English Metric Units, hvor én tomme er 914.400 EMU, og én centimeter er 360.000. Metafil-headere registrerer imidlertid deres ramme i enheder på 0,01 millimeter. Konverteringen mellem dem er en division med 360

Det er værd at nævne dette, fordi fejlen er stille. At konvertere via pixels ved 96 DPI i stedet — gange med 2540 og dividere med 9525 — giver en værdi 96 gange for stor, og intet afviser det: pakken er gyldig, billedet placeres korrekt af ankeret, og kun metafilens angivne ramme er meningsløs. EMU-modellen og dens afrundingsadfærd er dækket i billedgeometri, EMU-enheder og skalering

Åbn-og-gem af en projektmappe, der allerede har kameraer

At åbne og gemme en projektmappe bevarer kameraobjekter, inklusive udvidelseselementet og dets områdereference. Dette betyder mere end at oprette dem: de fleste projektmapper med kameraobjekter blev lavet i Excel af en analytiker, og et bibliotek, der stiltiende konverterer dem til almindelige billeder ved gemning, har ødelagt den levende adfærd, analytikeren var afhængig af

// Auditér, hvilke billeder er kameraer, og hvor de peger hen
for I := 0 to Sheet.Images.Count - 1 do
  if Sheet.Images[I].CameraRange <> '' then
    Writeln(Format('camera %d -> %s',
      [I, Sheet.Images[I].CameraRange]));

Når du genererer dashboards programmatisk, er auditeringen også regressionstesten: efter en gem-og-genåbn-cyklus skal det samme antal kameraer pege på de samme områder. Generel billed- og tegningshåndtering, inklusive ankermodellen der placerer dem, er dækket i diagrammer, billeder og tegninger

Hvornår et kamera slår alternativerne

Brug et kameraobjekt, når den samme levende tabel skal optræde på flere ark i forskellige størrelser, når et udskriftslayout har brug for en region af ét ark sammensat sammen med regioner fra andre, eller når en opsummeringsblok skal følge redigeringer foretaget andre steder uden en formel, der linker hver celle individuelt

Foretræk almindelige formler, når målet er en håndfuld celler, fordi en tvær-ark-formel er enklere, og ethvert værktøj forstår den. Foretræk et diagram, når dataene reelt er en serie frem for en formateret blok. Og foretræk et gengivet billede, når projektmappen skal forbruges af andre værktøjer end Excel, eller når øjebliksbilledet ikke må ændre sig efter levering — en arkiveret rapport bør ikke være levende

Én layoutbemærkning fra praksis: et kamera viser kildeområdet præcis som formateret, inklusive sammenlagte celler, betingede formater og kolonnebredder. At opnå en pænt udseende dashboard-blok begynder derfor med at formatere kildeområdet, som var det det færdige output, hvilket er den samme disciplin, der er beskrevet i sammenlagte celler og rapportskabelon-layout

Kameraobjekter, tegninger og XLSX-pakkeskriveren bag dem leveres i ét bibliotek til Delphi og C++Builder; den komplette funktionsliste findes på HotXLS Delphi spreadsheet component-siden