Teknisk artikel

Excel-kameraobjekt från Delphi: levande ögonblicksbilder

HotXLS skapar Excel-kameraobjekt på XLSX-kalkylblad från Delphi via AddCamera. Ett kameraobjekt är en bild som är permanent länkad till ett cellintervall: Excel återrenderar den från källintervallet varje gång arbetsboken öppnas eller källan ändras, så att en instrumentpanel kan visa en levande vy av en tabell som finns på ett annat blad, i valfri storlek, roterad om du vill

Funktionen finns i Excel som verktyget Kamera, en knapp de flesta användare aldrig har sett eftersom den inte ligger på menyfliksområdet som standard. Den löser ett verkligt instrumentpanelsproblem bättre än alternativen: ett kopierat intervall blir inaktuellt, ett diagram kan inte visa godtyckligt cellinnehåll, och en länkad bild inklistrad för hand kan inte genereras av kod. Ett kameraobjekt är den enda konstruktionen som är både levande och godtycklig

HotXLS-kameraobjekt skapat från Delphi: en levande bild av Data!$B$2:$D$4 placerad på ett instrumentpanelsblad som Excel återrenderar vid öppning och vid varje källredigering
Ett kameraobjekt förblir permanent länkat till sitt källintervall, så Excel återrenderar bilden vid öppning och vid varje redigering, i valfri storlek och från ett intervall på ett annat blad

Var dokumenteras detta, och varför spelar det roll?

Huvudspecifikationen för kalkylblad beskriver inte kameraobjekt; de behandlas som en implementationsdetalj. Den auktoritativa beskrivningen finns i dokumentationen för ritmarkup, under rubriken Camera Tool, och att veta det sparar en eftermiddag av att söka i fel dokument

Strukturellt är ett kameraobjekt ett vanligt bildelement vars icke-visuella bildegenskaper bär en tilläggslista. Tillägget identifieras av en fast GUID, och inuti det registrerar ett element från 2010-ritnamnrymden två saker: källintervallet som en absolut A1-stilsreferens, valfritt bladkvalificerad, och en formidentifierare. Allt annat med bilden är normalt

XLSX-anatomi för ett kameraobjekt skrivet av HotXLS från Delphi: ett vanligt bildelement vars tilläggslista bär ett element från 2010-ritnamnrymden som registrerar det absoluta källintervallet och en formidentifierare
Strukturellt är en kamera en vanlig bild plus ett tilläggselement från 2010-ritnamnrymden, som registrerar det absoluta A1-stilskällintervallet och en formidentifierare

Att skapa en

Två överlagringar finns eftersom två sätt att namnge ett intervall är praktiska. Textformen tar referensen exakt som den kommer att lagras, vilket är vad du vill ha för en källa på ett annat blad. Koordinatformen tar fyra cellkoordinater på samma blad och bygger den absoluta referensen åt 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];

    // Levande vy av Data!$B$2:$D$4, placerad över B10:F20 på instrumentpanelen
    Cam := Dashboard.AddCamera('Data!$B$2:$D$4', 10, 2, 20, 6);

    // Placeringsrutan använder som standard Excels egna 64 px breda kolumner
    // och 20 px höga rader; justera den ritade storleken i EMU efteråt vid behov
    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 returnerade objektet är ett normalt bildobjekt med en extra egenskap, CameraRange, som är icke-tom exakt när bilden är en kamera. Det är också så du upptäcker kameror i en arbetsbok du inte skapade själv: räkna upp bilderna och kontrollera egenskapen

Varför behöver platshållarbilden inte vara verklig?

Varje bild i ett XLSX-paket behöver en bilddel, och ett kameraobjekt är inget undantag. Men Excel ignorerar den bilden: vid inläsning återrenderar det det länkade intervallet och ritar resultatet. De inbäddade byten finns enbart som en visningscache för verktyg som inte implementerar kamerabeteendet

Det faktumet tar bort ett helt delsystem från implementationen. Det finns inget behov av att rastrera källintervallet, inget behov av en renderingsmotor för att producera ögonblicksbilden, och ingen risk att den cachade bilden skiljer sig från den levande i Excel. HotXLS skriver en minimal platshållarmetafil — en huvudpost och en slutpost, 108 byte totalt — vilket håller paketet strukturellt komplett och kostar ingenting

En konsekvens att planera för: en visare som renderar XLSX utan att implementera kameraobjekt visar platshållaren, som är blank. Om dina arbetsböcker konsumeras av ett sådant verktyg är ett kameraobjekt fel konstruktion och en renderad bild av intervallet är den rätta

Platshållarbilddel för ett HotXLS-kameraobjekt: Excel återrenderar det länkade intervallet vid inläsning och ignorerar den 108-byte stora metafilen, medan visare utan kamerastöd visar en blank bild
Excel ignorerar de inbäddade byten och återrenderar det länkade intervallet vid inläsning, så HotXLS skriver bara en 108-byte platshållarmetafil, medan en visare utan kamerastöd visar den blanka platshållaren

Enhetskonverteringen som är lätt att göra fel

Ritgeometri i Open XML mäts i English Metric Units, där en tum är 914 400 EMU och en centimeter är 360 000. Metafilhuvuden registrerar dock sin ram i enheter om 0,01 millimeter. Konverteringen mellan dem är en division med 360

Det är värt att nämna eftersom misstaget är tyst. Att istället konvertera via pixlar vid 96 DPI — multiplicera med 2540 och dividera med 9525 — ger ett värde 96 gånger för stort, och inget avvisar det: paketet är giltigt, bilden placeras korrekt av ankaret, och bara metafilens deklarerade ram är nonsens. EMU-modellen och dess avrundningsbeteende täcks i bildgeometri, EMU-enheter och skalning

Tur-och-retur för en arbetsbok som redan har kameror

Att öppna och spara en arbetsbok bevarar kameraobjekt, inklusive tilläggselementet och dess intervallreferens. Detta spelar större roll än att skapa dem: de flesta arbetsböcker med kameraobjekt gjordes i Excel av en analytiker, och ett bibliotek som tyst konverterar dem till vanliga bilder vid sparning har förstört det levande beteendet analytikern förlitade sig på

// Granska vilka bilder som är kameror och vart de pekar
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 genererar instrumentpaneler programmatiskt är granskningen också regressionstestet: efter en spara-och-öppna-igen-cykel måste samma antal kameror peka på samma intervall. Allmän hantering av bilder och ritobjekt, inklusive ankarmodellen som positionerar dem, täcks i diagram, bilder och ritobjekt

När en kamera slår alternativen

Använd ett kameraobjekt när samma levande tabell måste visas på flera blad i olika storlekar, när en utskriftslayout behöver en region från ett blad sammansatt tillsammans med regioner från andra, eller när ett sammanfattningsblock ska följa redigeringar gjorda på annat håll utan att en formel länkar varje cell individuellt

Föredra vanliga formler när målet är en handfull celler, eftersom en formel mellan blad är enklare och varje verktyg förstår den. Föredra ett diagram när datan verkligen är en serie snarare än ett formaterat block. Och föredra en renderad bild när arbetsboken kommer att konsumeras av andra verktyg än Excel, eller när ögonblicksbilden inte får ändras efter leverans — en arkiverad rapport ska inte vara levande

En layoutanmärkning från praktiken: en kamera visar källintervallet exakt som det är formaterat, inklusive sammanslagna celler, villkorsstyrd formatering och kolumnbredder. Att få ett rent instrumentpanelsblock börjar därför med att formatera källintervallet som om det vore den färdiga utdatan, vilket är samma disciplin som beskrivs i sammanslagna celler och layout för rapportmallar

Kameraobjekt, ritobjekt och XLSX-paketskrivaren bakom dem levereras i ett bibliotek för Delphi och C++Builder; den fullständiga funktionslistan finns på HotXLS Delphi kalkylbladskomponentsidan