Güncel bir Excel sürümünün kaydettiği bir grafik parçası, nadiren ECMA-376 grafik şemasının tanımladığı öğelerde durur. Grafik alanı çoğunlukla bir mc:AlternateContent bloğuyla açılır; o blok, yeni okuyuculara c14:style, eski okuyuculara düz bir c:style sunar; her seri bir c:extLst sürer ve içinde c16:uniqueId taşır ve "Value From Cells" veri etiketleri başka bir uzantıda yaşar. Yalnızca modellediğini ayrıştırıp kaydetme anında parçayı yeniden üreten bir program, bunların hiçbirini geri yazmaz. Başlıkta bir kelime değiştirin, dosyayı Excel'de yeniden açın ve bir hücre aralığından metin çeken etiketler gitmiştir
Çözüm, kaydetmeyi yeniden inşa saymaktan vazgeçmektir. Grafiğin geldiği baytları tutun; modelde hiçbir şey değişmemişse onları olduğu gibi geri yazın; değişmişse yeni öğeleri özgün ağaca birleştirin, böylece tanımadığınız parçalar Excel'in bıraktığı yerde kalır
Hiçbir şey değişmediğinde özgün ChartML'yi yeniden oynatmak
HotXLS, TXLSXWorkbook.PreserveUnsupportedParts True iken tam olarak bunu yapar; yeni oluşturulan bir çalışma kitabında bu zaten varsayılandır. İçe aktarmada her grafik, özgün UTF-8 baytlarını, uzunlukla birlikte ve tipleştirilmiş modelin temsil ettiği içeriğin 64 bitlik bir parmak iziyle tutar. Kaydetme anında HotXLS modellenmiş parçayı yeniden üretir, uzunluk ile parmak izini karşılaştırır ve ikisi de eşleşirse saklanan baytları harfiyen geri yazar: öğe sıralaması değişmez, boşluk kayması olmaz ve dokunulmamış her grafiğin ikinci bir UTF-16 kopyası bellekte tutulmaz
Karşılaştırma içerik üzerinde koştuğu için, bir özelliğin hâlihazırda taşıdığı değeri yeniden atamak hiçbir şey değiştirmez. TXLSXChart ayarlayıcıları eşit değerde erken çıkar; dolayısıyla bir veritabanı satırından her grafik başlığını "tazeleyen" bir döngü, başlığı zaten doğru olan her grafiği yine oynatır. Hata çubukları ve trend çizgilerindeki çizgi biçimlendirmesi kendi değişim bayrağıyla izlenir ve onu değiştirmek her zaman bir düzenleme sayılır
TXLSXChart.HasPreservedXml, herhangi bir şeyi düzenlemeden önce grafiğin hangi yolda olduğunu söyler. Grafiğe özgün ChartML bağlıyken True raporlar; bu, hem oynatmanın hem birleştirmenin ön koşuludur
var
Workbook: TXLSXWorkbook;
Chart: TXLSXChart;
begin
Workbook := TXLSXWorkbook.Create;
try
// Varsayılanı True; niyetin yeniden düzenlemeden sağ çıkması için açıkça ayarlayın.
// Open durumu kurduğu için bu, Open'dan önce yerinde olmalıdır
Workbook.PreserveUnsupportedParts := True;
Workbook.Open('quarterly-review.xlsx');
Chart := Workbook.Sheets[1].Charts[0]; // Sheets[] 1 tabanlıdır, Charts[] 0 tabanlı
if not Chart.HasPreservedXml then
Log('chart 0 has no original ChartML attached'); // Log sizin kendi yordamınızdır
Chart.Title := Chart.Title; // eşit değer: yine oynatılır
Workbook.Sheets[1].Charts[1].Title :=
'Revenue by region, Q3 2026'; // bu grafik birleştirme yolunu izler
Workbook.SaveAs('quarterly-review-out.xlsx');
finally
Workbook.Free;
end;
end;
Tek bir grafiği düzenlerken birleştirme neyi tutar?
Kısa cevap: tipleştirilmiş modelin sahip olmadığı her şey. Başlık, seriler, veri önbellekleri, çizim grupları ve eksenler modele aittir; dolayısıyla yeni üretilen ağaç onlara karar verir. Modellenmemiş öznitelikler, ad alanı bildirimleri, stiller, uzantı listeleri ve biçimlendirme düğümleri özgün ağaçtan gelir ve oturdukları eşleşen düğümlerin yanına yeniden yerleştirilir
Bir seriyi silin ve birleştirme, onu korunan XML'den diriltmemelidir; özgün ağaç o konumda hâlâ bir c:ser taşıyorsa bile. Modelin sahip olduğu her şey, modelin cevabı "gitti" olsa bile modelden alınır. Aynı şey öznitelik düzeyinde de geçerlidir: bilinen bir metin stilinin kalın, eğik, altı çizgili, üstü çizgili ya da font boyutu özelliğini temizlediğinizde birleştirme, eksik özniteliği temizlenmiş olarak okur ve b ya da sz'yi özgün defRPr'den geri kopyalamaz. Aynı öğedeki bilinmeyen öznitelikler yerini korur
Başlıklar aynı kuralı izler. İçe aktarmada HotXLS, c:title'nin yerleşik zengin metin çalıştırmalarını (rich runs) run başına fontları, boyutları ve dil etiketleriyle tutar ve metin el değmeden kaldıkça onları oynatır. Yeni bir Title atayın ve o zengin içerik düşer; başlık, TitleTextStyle'den biçimlendirilmiş tek bir run olarak yeniden yazılır. Eski run'ları yeni metne birleştirmek, yeni kelimelerin hangi run'a ait olduğunu tahmin etmek demektir ve buradaki bir tahmin, kimsenin yazmadığı başlıklar üretir
Şema sırası, Office'in üzerinde titiz olduğu yerlerde korunur. Bir extLst, şemanın gerektirdiği gibi ebeveynein son çocuğu kalır. İşaretleme uyumluluk blokları ayrı bir muamele görür: okuyucu mc:Choice'i atlar ve mc:Fallback'i okur; o fallback, modelin tanıdığı bir çizim grubuna sarıldığında birleştirme, yeni tipleştirilmiş içeriği fallback alt ağacının içine geri yazar. Naif bir birleştirme, düzenlenmiş çizim grubunu yayarken eski kopyayı fallback dalının içinde bırakır; kaydedilen grafik aynı grubu iki kez taşır
ClearPreservedXml ile tek bir grafiği hariç tutmak
TXLSXChart.ClearPreservedXml, tek bir grafik için özgün XML'i ve parmak izini düşürür ve bir sonraki kaydetme, o grafiği tamamen tipleştirilmiş modelden yeniden kurar. Bu, grafik başına bir karardır. PreserveUnsupportedParts, korunum durumunun içe aktarmada kurulup kurulmayacağını yönetmeye devam eder ve grafiklerden başka desteklenmeyen paket parçalarını da kapsar; tek bir temiz grafik için onu kapatmak yanlış kaldıraçtır
Bir grafiği, atmak işlemin amacıyken temizleyin; örneğin emekliye ayrılmış kurumsal bir temadan biçimlendirme hâlâ taşıyan bir şablon grafiği. Hata ayıklama refleksiyle dokunmayın. Bir düzenlemeden sonra yanlış çizilen grafik çoğunlukla bir modelleme sorunudur ve korunan XML'i temizlemek, Excel'in baştan yazdığının tek kopyasını çöpe atar
Tek bir durum önce kontrol ister. Bir hata çubuğu ya da trend çizgisi, tipleştirilmiş modelin ifade edemediği bir çizgi biçimlendirmesi kullanıyorsa LineAppearanceSupported özelliği False'tır; modelin dışında biçimlendirmesi olan bir trend çizgisi etiketi aynı şeyi LabelAppearanceSupported ile raporlar. HotXLS ikisini de sessizce daha sade bir sürümle değiştirmez: grafiğin üzerine düşebileceği korunan XML kalmadığında kaydetme, ifade edilemeyen çizgi ya da etiket görünümünü adlandıran bir EArgumentException ile durur. Temizlemeden önce ikisini sınamak bir döngüdür
// Kendi yardımcınız, HotXLS'in parçası değil: her hata çubuğu çizgisi,
// trend çizgisi ve trend etiketi yalnızca tipleştirilmiş modelden yazılabiliyorsa True
function ChartRebuildable(Chart: TXLSXChart): Boolean;
var
I, T: Integer;
S: TXLSXChartSeries;
begin
Result := False;
for I := 0 to Chart.SeriesCount - 1 do // her çizim grubunu kapsar
begin
S := Chart.Series[I];
if (S.ErrBarX <> nil) and not S.ErrBarX.LineAppearanceSupported then Exit;
if (S.ErrBarY <> nil) and not S.ErrBarY.LineAppearanceSupported then Exit;
for T := 0 to S.TrendlineCount - 1 do
begin
if not S.Trendlines[T].LineAppearanceSupported then Exit;
if not S.Trendlines[T].LabelAppearanceSupported then Exit;
end;
end;
Result := True;
end;
// ...
Chart := Workbook.Sheets[1].Charts.FindByName('Old theme chart');
if (Chart <> nil) and ChartRebuildable(Chart) then
Chart.ClearPreservedXml // sonraki kaydetme bu grafiği modelden yeniden kurar
else
Log('kept original ChartML for this chart');
AddPlotGroup ve ikincil eksenle kombinasyon grafikleri
TXLSXChart.AddPlotGroup, kendi grafik ailesine ve kendi birincil ya da ikincil eksen atamasına sahip, sıralı bir çizim grubu ekler. Bu, her finans ekibinin istediği grafiği kapsar: gelir sol eksende sütunlar, marj yüzdesi sağda bir çizgi. Her grafik ValueAxis, CategoryAxis, SecondaryValueAxis, SecondaryCategoryAxis ve SeriesAxis'i açar; konum, eksen tanımlayıcıları, kesişim, tarih birimleri, etiket aralıkları, sayı biçimi ve görünürlük için tipleştirilmiş ayarlarla
Tek türden grafiklerin düz API'si hâlâ oradadır ve gruplara eşlenir. ChartType ile AddSeries ilk çizim grubuna hitap eder; SeriesCount ile Series[], her grubun serilerini sırayla gezer; yukarıdaki yardımcının çizgi serisini de görmesinin nedeni budur. Sıranın önemsediği tek yer vardır. TXLSXCharts.Add, hiç çizim grubu olmayan bir grafik kurar ve AddSeries'in ya da AddPlotGroup'un hangisi önce koşarsa birinci grubu o kurar. Taze bir grafikte önce AddPlotGroup(xlsxChartLine, xlsxAxisSecondary) çağırın: çizgi birinci grup olur, grafik türü çizgiye döner ve sonradan eklediğiniz gelir serisi ona düşer. İki grubu da açıkça kurmak belirsizliği kaldırır; örnek tam olarak bunu yapar
var
Chart: TXLSXChart;
Columns, Line: TXLSXChartPlotGroup;
begin
// 1..15 satırları, 5..12 sütunları üzerine demirli; henüz çizim grubu yok
Chart := Sheet.Charts.Add(xlsxChartColumn, 'Revenue and margin',
1, 5, 15, 12);
Columns := Chart.AddPlotGroup(xlsxChartColumn); // grup 1, birincil
Columns.AddSeries('Revenue', 'Data!$A$2:$A$13', 'Data!$B$2:$B$13');
Line := Chart.AddPlotGroup(xlsxChartLine, xlsxAxisSecondary); // grup 2
Line.AddSeries('Margin %', 'Data!$A$2:$A$13', 'Data!$C$2:$C$13');
Line.ZOrder := 1; // çizgiyi sütunların önüne çiz
Chart.SecondaryValueAxis.NumberFormat := '0%';
Chart.SecondaryValueAxis.NumberFormatSourceLinked := False;
Chart.SecondaryValueAxis.MinValue := 0;
Chart.SecondaryValueAxis.MaxValue := 0.5;
// Grafik alanının grafik içindeki oransal konumu: x, y, genişlik, yükseklik tek çağrıda
Chart.PlotAreaLayout.SetPositionAndSize(0.08, 0.12, 0.80, 0.72);
end;
Çizim grubundaki ZOrder, katmanlamayı denetler: grafik yazıcısı, c:barChart ile c:lineChart bloklarını yaymadan önce grupları ona göre sıralar; küçük değerler arkada kalır. Sıralı her grup modelde olduğu için bir kombinasyon grafiğini açıp yeniden kaydetmek, her grafik ailesini ikincil, tarih ve seri eksenleriyle birlikte tutar. Grafik formül başvuruları ve önbelleklenmiş seri değerleri çalışma kitabı kopyalarında ve aç-kaydet döngülerinde yaşar; grafik demirleri, grafik parçalarıyla ilişki tanımlayıcısından eşlenir, böylece ilişki girdilerini başka bir aracın yeniden sıraladığı bir paket bile her grafiği kendi çalışma sayfası konumuna koyar
Office elle yapılmış bir düzeni neden yok sayar?
Çünkü koordinatlar eksik gelmiştir. Office, x, y, w ve h'den herhangi biri bir c:manualLayout içinde mevcutken dördünü eksiksiz bir grup olarak ister; aksi halde bütün öğeyi yok sayar. Şema dördünü de isteğe bağlı sayar; dolayısıyla yalnızca x ile y taşıyan bir dosya geçerlidir ve Excel'de yine de hiçbir şey yapmaz
TXLSXChartLayout.SetPositionAndSize kullanılacak çağrıdır. Dört değeri ayarlar, dört mod öğesini var olarak işaretler ve düzeni tek adımda etkinleştirir. Tekil X, Y, Width ve Height özellikleri birer değer ayarlar ve HotXLS tam olarak var olan öğeleri yazar; bir dosyayı okurken dokuz isteğe bağlı çocuğun varlığını koruduğu gibi. Bu, dokunulmamış bir düzenin kaynağına sadık kalmasını sağlar. Aynı zamanda iki özellik atamasından kurulan bir düzenin iki koordinatla yazılacağı ve Office'in onu atlayacağı anlamına gelir. Aynı TXLSXChartLayout sınıfı PlotAreaLayout, TitleLayout, LegendLayout ve her eksenin TitleLayout'unun arkasındadır
İki varsayılan, spesifikasyonun izin verdiğinin tamamını değil, Excel'in yaptığını izler. edge'i XMode ile YMode için, factor'ü WidthMode ile HeightMode için kullanır; standart öteki kombinasyonlara izin verir ama Excel konumları kenar, boyutları çarpan olarak kaydeder ve kaydederken ötekini dönüştürür. layoutTarget (Target, iç ya da dış) grafik alanı için yazılır; başlık, eksen başlığı ve gösterge belgesi düzenleri onu bırakır, çünkü Microsoft'un grafik şeması için uygulama notları, o öğeler altında buna izin vermez
Bir çalışma kitabı gidiş-dönüşüne oturtmak
Grafik korunumu daha geniş bir kuralın tek örneğidir: başka bir yerde yazılmış belgeleri düzenleyen bir kütüphane, kendisinden isteneni değiştirmeli ve gerisini bulduğu gibi bırakmalıdır. HotXLS aynı akıl yürütmenin temalar, hesaplama zincirleri ve çalışma sayfası uzantılarına uygulanmış halini tema, extLst ve calcChain için kayıpsız gidiş-dönüşler yazısında, VBA projeleri ve dış bağlantılara uygulanmış halini ise VBA ve dış bağlantıların korunumu yazısında ele alır. Sıfırdan grafik kurmak, resim yerleştirmek ve şekil çizmek için HotXLS'te grafikler, resimler ve çizimler yazısına bakın
HotXLS, XLSX grafiklerini makinede Excel olmadan yerel Delphi ve C++Builder kodundan okur, düzenler ve yazar; grafik sadakati bir otomasyon sunucusuna değil kütüphaneye karar verir. Grafik API referansı ve deneme sürümü HotXLS Delphi elektronik tablo bileşeni sayfasındadır