Teknik Makale

Delphi'de HotXLS ile Bir XLSX Çalışma Sayfasını Çoğaltma

Bir sayfayı tam istediğiniz gibi hazırladınız. Başlık bandı birleştirilmiş, sütun genişlikleri veriye uyuyor, ilk iki satır dondurulmuş, temiz bir A4 dışa aktarımı için yazdırma alanı ve kenar boşlukları ayarlanmış, ayrıca finans ekibi kolay bulsun diye sekme renklendirilmiş. Şimdi raporun bundan on iki tane, her bölge için bir tane olacak şekilde aynı düzenden başlaması gerekiyor. Bu sayfayı kodda on iki kez yeniden kurmak, ince kaymaların sisteme sızdığı yerdir: 7. bölgedeki sütun bir punto daha dar olur, 11. bölge dondurmayı kaybeder ve bunu kimse PDF bir yöneticinin masasına inene kadar fark etmez. Aslında istediğiniz şey, Excel'deki sağ tık, Taşı veya Kopyala, Bir kopya oluştur akışının programatik karşılığıdır: bitmiş sayfayı alıp birbirinden bağımsız kopyalar üretmek

HotXLS içindeki XLSX motoru, Excel'in kendisini otomatikleştirmeden Excel dosyalarını okuyup yazan yerel bir Delphi ve C++Builder kütüphanesi olarak, zaten sayfaları taşıyabiliyor, silebiliyor ve sayfalar arasında hücre aralıklarını kopyalayabiliyordu. v2.91.0'a kadar tek çağrıyla tüm bir çalışma sayfasını klonlayamıyordu. Bu sürüm iki giriş noktası ekliyor: TXLSXWorksheet.CopyFrom, bir çalışma sayfasından diğerine sayfa düzeyindeki durumu kopyalar, ve TXLSXSheets.Duplicate, yeni bir sayfa ekleyip sizin yerinize CopyFrom çalıştırır. İlginç olan şey yalnızca bir şeyleri kopyalaması değildir. Asıl önemli nokta, nelerin derin kopyalanıp nelerin kopyalanmadığı arasına bilinçli olarak çizilen sınır ve bu sınırın neden tam burada olduğudur

Bitmiş bir sayfayı klonlamak için tek çağrı

Yüksek seviyeli işlem Duplicate şeklindedir. Kaynak sayfanın 1 tabanlı dizinini verirsiniz ve özgün düzeni ile veriyi yansıtan yepyeni bir çalışma sayfası döndürür. Dizin kuralı XLSX tarafındaki Items[] ile aynıdır, bu yüzden ilk sayfanın dizini 1 olur, 0 değil; aralık dışı bir dizin verirseniz istisna yerine nil alırsınız ve bu, XLSX sayfa koleksiyonunun geri kalanında kullanılan aynı hata sözleşmesidir

var
  Book: TXLSXWorkbook;
  Template, Copy: TXLSXWorksheet;
begin
  Book := TXLSXWorkbook.Create;
  try
    Template := Book.Sheets.Add('Template');
    Template.Cells[1, 1].Value := 'Quarterly Statement';
    Template.Range['A1:C1'].Merge;
    Template.ColWidth[1] := 18;
    Template.FreezePanes(2, 1);          // freeze top row + first column
    Template.TabColorIsAuto := False;
    Template.TabColor := $FF1F4E79;

    // Clone with an explicit name...
    Copy := Book.Sheets.Duplicate(1, 'Region-North');
    // ...or let it pick the Excel-style default name.
    Copy := Book.Sheets.Duplicate(1);    // -> "Template (2)"

    Book.SaveAs('regions.xlsx');
  finally
    Book.Free;
  end;
end;

Bu parçacıkta üzerinde durmaya değer iki nokta var. Birincisi, FreezePanes bağımsız değişkenlerini önce satır sonra sütun olacak şekilde alır, FreezePanes(ARow, ACol), dolayısıyla Cells[Row, Col] dizinlemesiyle hizalanır; kopya tam olarak aynı dondurma ayrımını devralır. İkincisi, yöntemin adı Duplicate olarak seçilmiştir, daha bariz görünen Copy değildir, ve bu bir stil tercihi değildir. Copy, System birimindeki standart bir yordamdır ve dizgilerle dinamik diziler için sürekli kullanılır. Bir sınıf üzerinde Copy adlı bir yöntem, yöntem gövdeleri içinde bunu gölgeler ve tam da altı ay sonra sizi vuran türden bir çözümleme belirsizliği yaratır. Duplicate tüm sorunu baştan savuşturur ve çağrı noktasında da doğru okunur

Varsayılan ad Excel'in kendi kuralını izler

Tek bağımsız değişkenli aşırı yüklemeyi çağırdığınızda ya da boş bir ad dizesi verdiğinizde, yeni sayfa kaynak sayfanın adına (2) son eki eklenerek adlandırılır ve ad benzersiz olana kadar bu son ek artar. Template sayfasını bir kez çoğaltırsanız Template (2) elde edersiniz; yeniden çoğaltırsanız Template (3) elde edersiniz, çünkü Template (2) adı zaten alınmıştır. Bu davranış, Excel'in kendi Bir kopya oluştur komutuyla ürettiği adları yansıtır; böylece kodunuzun ürettiği çalışma kitabı, bir kullanıcının elle çoğaltılmış bir kitaptan beklediği gibi görünür. Benzersizlik denetimi canlı sayfa koleksiyonu üzerinde çalışır, bu da yalnızca daha önceki çoğaltmaların değil, sizin elle oluşturduğunuz adların da atlanacağı anlamına gelir

Bölge başına veya ay başına bir sayfa üretiyorsanız, bunun yerine açık ad veren aşırı yüklemeyi kullanın. Tahmin edilebilir bir Region-North, Region-South düzeni, sonradan ele alınması (2), (3) son ekleri dizisinden daha kolaydır ve tanımlı adlarla sayfalar arası formülleri okunaklı tutar

CopyFrom neleri derin kopyalar

Arka planda Duplicate sayfayı ekler ve ardından CopyFrom(ASource) çağırır; bunu, zaten oluşturduğunuz bir sayfanın üzerine klonlamak istediğinizde doğrudan da çağırabilirsiniz. CopyFrom iki bozulmuş durumu en başta koruma altına alır: nil içinden kopyalama ya da bir sayfayı kendi üzerine kopyalama, her ikisi de hemen döner ve hiçbir şey yapmaz. Bundan sonrası kopyalamanın kendisidir ve kapsamı bilinçli olarak geniş tutulmuştur

Önce hücre verileri gelir. CopyFrom kaynak taraftan UsedRange değerini, yani doldurulmuş hücreler ile birleştirilmiş bölgelerin sıkı sınırlayıcı kutusunu ister ve mevcut CopyRangeTo mekanizmasını yeniden kullanarak her değeri, formülü ve hücre başına stil dizinini hedefte A1 noktasından başlayacak şekilde taşır. Hücrelerin üzerine, şablonu bitmiş gösteren sayfa düzeyindeki durum katmanının tamamını yeniden oynatır:

  • Birleştirilmiş aralıklar, başlık bandı aynı dikdörtgeni kapsasın diye koordinatlara göre yeniden oluşturulur
  • Sütun genişlikleri ve satır yükseklikleri, ayrıca gizli, daraltılmış ve anahat düzeyi listeleri, varsayılan olmayan satır ve sütunlar tam hizalı kalsın diye birebir kopyalanır
  • Bölmeleri dondurma ve görünüm durumu: yakınlaştırma düzeyi, kılavuz çizgisi ve sıfır değeri gösterimi, sağdan sola yön ve görünüm tipi
  • Koruma durumu, eylem bazlı izin seçenekleriyle birlikte, böylece kilitli bir şablon aynı biçimde kilitli kalır
  • Tüm sayfa ayarı bloğu: kenar boşlukları, yönlendirme, kağıt boyutu, ölçekleme ve sayfaya sığdırma, yazdırma alanı, yazdırma başlıkları, üstbilgi ve altbilgiler ile yazdırma kılavuz çizgileri ve yazdırma başlıkları bayrakları
  • AutoFilter aralığı, sekme rengi ve sayfanın görünürlüğü

Sonuç, kaynağıyla aynı şekilde yazdıran, filtrelenen ve sunulan bir sayfadır. Hücreler, birleştirmeler ve boyut listeleri takma ad verilmeden fiziksel olarak yeni sayfada yeniden oluşturulduğu için kopya tamamen bağımsızdır. Kopyadaki bir hücreye 999 yazarsanız kaynak kendi özgün değerini korur; paralel bölgesel raporlar için tasarlanmış bir klonun en önemli özelliği bu bağımsızlıktır ve birlikte gelen SheetCopy demosu bunu açıkça doğrular

Neleri yüzeysel bırakır ve neden

Şimdi dürüst kısmı. Grafikler, gömülü görseller, XLSX tabloları, veri doğrulamaları ve koşullu biçimlendirme kuralları kopyalanmaz. Bu, gözden kaçmış bir eksik değil; belgelenmiş ve bilinçli bir sınırdır. Bu gerekçeyi anlamaya değer, böylece şaşırmak yerine planınızı ona göre kurabilirsiniz

Bu koleksiyonların her biri, saf bir alan kopyasından sağ çıkmayan kimlikler ve başvurular taşır. Bir grafik kaynak veri aralığını işaret eder ve OOXML paketinde bir çizim ilişkisine sahiptir; nesneyi ilişkiyi ve seri başvurularını yeniden eşlemeden klonlamak, yanlış veriye göre işlenen bir grafik ya da Excel'in onarım istediğini belirttiği bir paket üretir. Bir tablonun çalışma kitabı içinde benzersiz olması gereken bir adı, belirli sütunlara bağlı bir başlık satırı ve kendine ait otomatik oluşturulmuş bir ilişkisi vardır. Koşullu biçimler ve veri doğrulamaları koordinat aralıklarına bağlanır ve doğrulama durumunda formülle başka aralıklara başvurabilir. Bunların herhangi birini doğru biçimde derin kopyalamak, başvuruları yeniden yazmak ve yeni kimlikler üretmek demektir; bu da gerçek çalışma ve gerçek hata modları anlamına gelir. Yalnızca nesneyi kopyalayıp başvurularını kopyalamamak gibi yarım bir çözüm, hiç kopyalamamaktan daha kötüdür: dosya onarım istemiyle açılır ve içeriği sessizce düşürür. Bu yüzden motor, temiz biçimde kopyalayabildiği şeyleri kopyalar ve başvuru taşıyan koleksiyonları, hedefin neyi işaret etmesi gerektiğini bilen çağırana bırakır

Pratikte bu, daha zengin bir şablon için iş akışının şu olduğu anlamına gelir: hücreleri, düzeni ve yazdırma ayarlarını almak için sayfayı çoğaltın; ardından grafiği, tabloyu, doğrulamaları veya koşullu biçimleri, ilk kez oluştururken kullandığınız API'nin aynısıyla kopya üzerinde yeniden kurun. Bunları kopyanın kendi aralıklarına karşı yeniden oluşturduğunuz için başvurular tasarım gereği doğru çıkar. A1:C10 okuyan bir grafik için, kopya üzerinde kopyanın kendi A1:C10 aralığını işaret eden yeni bir grafik ekleyin; canlı bir AutoFilter istiyorsanız, filtre aralığı taşınır, bu yüzden yalnızca sütun ölçütlerini yeniden uygularsınız. Koşullu biçimlendirme ve veri doğrulama kurallarını da, birleştirilmiş hücreler ve rapor şablonu düzeni hakkındaki makalede açıklanan aynı çağrılarla yeniden eklersiniz; o makale, kopyanın devraldığı birleştirme tablosu ile aralık modelini ele alır

Çoğaltmanın raporlama hattındaki yeri

Çalışma sayfası çoğaltma, yer tutucu odaklı üretimin doğal eşidir. Delphi'de şablon tabanlı rapor üretimi kılavuzundaki belirteç sabitlemeli yaklaşım, veriyi başkalarının düzenlediği bir düzene yazma sorununu çözer; çoğaltma ise aynı düzene tek bir çalışma kitabında birçok kez ihtiyaç duyma sorununu çözer. İkisini birleştirdiğinizde desen nettir: belirteçleri, birleştirmeleri ve yazdırma ayarlarıyla birlikte bozulmamış tek bir Template sayfası tutun, ardından her bölge veya dönem için Duplicate çağırın, klondaki belirteçleri o veri dilimiyle doldurun ve devam edin. Bozulmamış şablon asla değiştirilmez, bu yüzden bir sonraki klon için güvenilir kaynak olarak kalır ve her çıktı sayfası bayt bayt aynı düzenden başlar

Bir sıralama notu, belirli bir karışıklık sınıfını önler. Sayfayı veriyi doldurmadan önce çoğaltın, sonra değil. Bir şablon son çeyreğin rakamlarını değil yapı ile biçimlendirmeyi tutmalıdır ve boş stilli bir sayfayı klonlamak, her kopyanın temiz başlamasını sağlar. Zaten veri taşıyan bir sayfayı çoğaltırsanız o veri de gelir, çünkü CopyFrom kullanılan aralığı sadakatle kopyalar; bu bazen istediğiniz şeydir ama birden çok rapora yayılım işinde genellikle değildir

Hızlı bir doğrulama alışkanlığı

Derin kopya ile yüzeysel kopya arasındaki ayrım siz özellikle bakana kadar görünmez olduğu için, her şeyin taşındığına güvenmek yerine işe beş satırlık bir kontrol ekleyin. Çoğaltmadan sonra, klonun devralması gereken yapısal sinyalleri geri okuyun ve kaynakla eşleştiğini doğrulayın

Copy := Book.Sheets.Duplicate(1, 'Region-North');
WriteLn(Format('merged=%d  colA=%.1f  freezeRow=%d  tabAuto=%d',
  [Copy.MergedCells.Count, Copy.ColWidth[1],
   Copy.FreezeRow, Integer(Copy.TabColorIsAuto)]));
// Prove independence: mutate the copy, confirm the source is untouched.
Copy.Cells[2, 2].Value := 999;
// Template.Cells[2, 2].Value is still whatever it was.

Birleştirme sayısı, bir sütun genişliği, dondurma satırı ve sekme rengi bayrağı, gerçekten kopyalanan katmanın taşındığını gösterir. Ayrı olarak, grafik, tablo, doğrulama veya koşullu biçimlendirme taşıyan her sayfada bunları kopya üzerinde yeniden oluşturulacaklar listesi olarak görün: yoklukları tasarım gereğidir ve çözüm birkaç çağrıdır, hata raporu değil. Güvenli olduğu yerde derin, başvuruların kırılacağı yerde yüzeysel yaklaşımı, bu özelliği iyi kullanmanın bütün hikayesidir

Çalışma sayfası çoğaltma ve burada anlatılan CopyFromsayfa durumu kopyalama özelliği, yerel HotXLS Delphi spreadsheet componentSheetCopy içinde v2.91.0 ile sunulmuştur; buna, klonla ve değiştir döngüsünü baştan sona çalıştıran kullanılabilir bir