Teknik Makale

HotXLS ile Delphi'de Excel Açıklamaları ve Köprüleri

Üretilmiş bir çalışma kitabında bir sayfanın adını "Summary" iken "Overview" yapın; Summary!A1 hedefini gösteren her belge içi köprü hiçbir yere gitmez olur. Kaydederken istisna yok, açarken de yok. Bağlantı hâlâ görünür, hâlâ tıklanabilir durur ve sessizce hiçbir şeye çözülür. Aynı tür bozulma, farklı kaydetme dönüşümünden ya da bir .xls ile .xlsx gidiş dönüşünden sonra da ortaya çıkar; bir açıklama bir sütun kayar ya da göreli bir bağlantı hedefini düşürür. Her iki özellik de gerçek insanların üzerine iş yaptığı gözden geçirme durumunu taşır, dolayısıyla bozulduklarında hata, bir gözden geçiren tıklayıp hiçbir şey olmayana kadar görünmez kalır

Açıklamaların ve köprülerin, görünüşteki süsleyici hâllerinin düşündürdüğünden fazla özen hak etmesinin pratik nedeni budur. HotXLS, Delphi ve C++Builder koduna her ikisi için de XLS ve XLSX içinde, döngüde hiç Excel otomasyonu olmadan doğrudan yazma erişimi verir. Bu denetimin öbür yüzü sorumluluktur: kütüphane tam olarak verdiğiniz hedefleri yazar ve hiçbirini doğrulamaz, dolayısıyla bir gözden geçirme akışını sağlam tutmak Excel'in değil, kodunuzun işidir

Makine yazımı gözden geçirme kaydı olarak hücre açıklamaları

XLSX sınıf modelinde bir açıklama, çalışma sayfası düzeyinde bir nesnedir: satırını, sütununu, bir yazarı ve bir metin gövdesini bilir. Yazar alanı ekmeğini çıkarır. Kodunuzun ürettiği bir çalışma kitabı bir gözden geçirme zincirinden geçtiğinde, bir denetçinin sorduğu ilk soru belirli bir notu kimin yazdığıdır ve yazarsız bırakılmış bir not bu soruyu boşlukla yanıtlar. Üretilen açıklamaları bir hizmet kimliğiyle damgalayın ki kaynak hiçbir zaman belirsiz kalmasın

Delphi HotXLS içinde bir açıklama yeniden denemesinin şeması: FindAt yoklaması var olan hücre notunu güncellerken körü körüne yapılan AddComment yeniden denemesi yinelenmiş bir not bindirir
AddComment çağrısını körü körüne yapan bir yeniden deneme aynı hücreye ikinci bir not bindirir, FindAt yoklaması ise orada zaten duran notu düzenler
var
  Book: TXLSXWorkbook;
  Sheet: TXLSXWorksheet;
  Note: TXLSXComment;
begin
  Book := TXLSXWorkbook.Create;
  try
    Book.Open('reconciliation.xlsx');
    Sheet := Book.Sheets[0];

    // Düzeltilmiş rakam üzerinde yazarı belli bir not
    Sheet.AddComment(14, 4, 'Manual adjustment: late FX rate, see ticket FIN-2214',
      'recon-service');

    // İkinci bir not bindirmek yerine var olan notu güncelle
    Note := Sheet.Comments.FindAt(14, 4);
    if Note <> nil then
      Note.Text := Note.Text + ' [verified 2026-06-11]';

    Book.SaveAs('reconciliation-reviewed.xlsx');
  finally
    Book.Free;
  end;
end;

FindAt yoklaması göründüğünden çok yük taşır. Geçici bir hatadan sonra yeniden deneyen bir toplu iş, zaten açıklama eklediği bir hücrede seve seve ikinci kez AddComment çağırır ve hücre, kimsenin istemediği iki bindirilmiş notla kalır. Önce FindAt ile yoklayın ve döndürdüğü nesneyi güncelleyin. Comments koleksiyonu ayrıca DeleteAt ve DeleteInRange sunar. Bir çalışma kitabını binadan çıkmadan önce temizlerken uzanacağınız şey o aralık çeşididir: bütün bir bölgedeki iç kalite notlarını silmek, hücreler üzerinde elle yazılmış bir döngü yerine tek bir çağrıdır

Dış URL bağlantıları ile çalışma kitabı içi atlamalar farklı API bileşenleridir

OOXML iki bağlantı türünü farklı yerlerde tutar. Dış bir URL, sayfanın .rels parçasında bir ilişki girdisine dönüşür ve hücre ilişkiyi kimliğiyle gösterir. Belge içi atlama ise ilişki katmanına hiç dokunmaz; doğrudan bağlantı üzerinde saklanan Summary!A1 gibi düz bir konum dizesidir. HotXLS bu ayrımı tek bir yöntemi aşırı yüklemek yerine API içinde görünür tutar, yani doğru çağrıyı hedefin nerede yaşadığını bilerek seçersiniz:

Delphi ile üretilen çalışma kitaplarında HotXLS içinde dış bir URL bağlantısının rels parçasında ilişki olarak, belge içi atlamanın ise düz konum dizesi olarak nasıl saklandığını karşılaştıran şema
Dış bir URL ilişki katmanından geçer, belge içi atlama ise düz metindir; dolayısıyla her tür kendince bozulur ve kendi denetim kuralını ister
Sheet.Cells[2, 1].Value := 'Source record';
Sheet.AddHyperlink(2, 1, 'https://intranet.example.com/records/2214',
  'Open record 2214', 'ERP source entry');

Sheet.Cells[3, 1].Value := 'Totals';
Sheet.AddHyperlinkToCell(3, 1, 'Overview!B12', 'Jump to totals');

Ortaya çıkan TXLSXHyperlink nesnesinde Url ile Location birbirini dışlar ve hangisinin dolu olduğunu IsInternal söyler. Açılmış bir çalışma kitabındaki bağlantıların envanterini çıkarırken ve "dosyadan çıkanlar" ile "dosyada kalanlar" için farklı kurallar uygulamanız gerektiğinde denetlediğiniz bayrak odur: dış bir ana bilgisayar bir izin listesiyle karşılaşabilirken, belge içi bir hedefin yalnızca var olan bir sayfayı adlandırması yeter. Belge içi bağlantıların ardında ilişki parçaları bulunmaz, bu da onları toplu olarak yeniden yazmayı ucuzlatır

Girişteki bozulma tümüyle belge içi tarafta yaşar ve tek bir olgudan doğar: bir konum dizesi ayrıştırılmış bir başvuru değildir. HotXLS ona verdiğiniz metnin tam olarak kendisini yazar ve bir sayfa sonradan yeniden adlandırıldığında o metni hiçbir şey yeniden yönlendirmez. Uygulamada iki savunma ayakta kalır. Birincisi sıralama disiplinidir: tek bir bağlantı üretmeden önce her sayfayı yeniden adlandırın, sonra sayfa adlarını donmuş tanımlayıcılar gibi ele alın. İkincisi daha sağlamdır ve sonradan yapılan yeniden adlandırmalardan sağ çıkar. Bağlantıyı ham bir Sheet!Cell adresi yerine çalışma kitabı düzeyinde tanımlanmış bir ada yöneltin, çünkü Excel altındaki sayfa değiştiğinde adın tanımını yeniden yazar ve bağlantı da kendiliğinden onunla birlikte gelir. Bu ikinci yaklaşım, HotXLS içinde tanımlanmış adlar ve sayfalar arası formüller yazısındaki tekniklerle doğal biçimde eşleşir

XLS tarafı: aynı kavramlar, daha eski tesisat

BIFF8 cephesi açıklamaları çalışma sayfası düzeyinde bir koleksiyon yerine aralıklara asar. Bir IXLSRange üzerinde AddComment çağırır ve karşılığında bir TXLSComment alırsınız; aralığın Comment özelliği var olan bir notu okur, ClearComments ise onları siler. Buradaki keskin kenar konumsaldır. Bir TXLSComment kendi satırını ve sütununu dışarıya açmaz, dolayısıyla doğal görünen "her açıklamayı dolaş ve nerede durduğunu bildir" döngüsü API karşısında tersten işler. Hücrelerden başlamak zorundasınız. Denetimi ya açıklama eklediğiniz adres listesinden sürün ya da yazarken kendi konum günlüğünüzü tutun, çünkü açıklama nesnesi sonradan size nerede yaşadığını söylemez

var
  Book: IXLSWorkbook;
  Sheet: IXLSWorksheet;
  Remark: TXLSComment;
begin
  Book := TXLSWorkbook.Create;
  Sheet := Book.Sheets.Add;
  Sheet.Name := 'Review';
  Sheet.Cells.Item[5, 2].Value := 4821.50;

  Remark := Sheet.Cells.Item[5, 2].AddComment('Awaiting sign-off from controller');
  Remark.Visible := True;   // ilk görüntülemede notu açık göster

  Sheet.AddHyperlink(7, 2, 'https://intranet.example.com/signoff/4821',
    'Sign-off form', 'Opens the controller queue');
  Book.SaveAs('review.xls');
end;

Visible değerini True yapmak, bir notun gözden kaçmasını imkânsızlaştırmanın eski yoludur: sarı kutu, imlecin üzerine gelmesini beklemek yerine sayfada açık kalır. TXLSComment, XLSX karşılığından bir adım öteye giderek TextRuns sunar, böylece tek bir not kalın bir uyarıyı düz bir açıklamanın yanında taşıyabilir; XLSX açıklama API bileşeni bu biçimlendirmeyi aynı şekilde açığa çıkarmaz. Bu taraftaki köprüler üç aşamalı aşırı yüklemeyle gelir (yalnızca adres, sonra görünen metinle, sonra ekran ipucuyla) ve her bağlantının Address, SubAddress, DisplayText ve ScreenTip alanlarını yüzeye çıkardığı, çalışma sayfasının HyperLinks koleksiyonu üzerinden geri okunur

Bir gözden geçirme dizini sayfası, dağınık notlardan iyidir

Bir düzine kadar açıklamayı geçince, üzerine gelip okuma sessizce ölçeklenmez olur. Notlar, bir gözden geçirenin hiç açmadığı sayfalarda birikir ve en çok önem taşıyanlar tam da gözden kaçması en kolay olanlardır. En iyi dayanan yapı, üretilmiş bir dizin sayfasıdır: açıklama eklenmiş her konum için bir satır; sayfa adını, hücre adresini, yazarı ve notun kısa bir alıntısını listeler. Son sütun, doğrudan açıklamalı hücreye atlayan ve AddHyperlinkToCell ile kurulmuş belge içi bir köprü taşır. Artık gözden geçiren bir kılavuzda avlanmak yerine bir listeyi aşağı doğru okur ve o dizinin satır sayısı, aşağıdaki denetim geçişi için açıklama envanteriniz olarak da iş görür

Dizini kurmak ucuzdur, çünkü üreticiniz dokunduğu her konumu zaten bilir. Her açıklamayı yazarken bir listeye (sayfa, satır, sütun, yazar, özet) demeti ekleyin, sonra dizin sayfasını en son üretin ki kaydetmeden önce satır sayısı kesinleşsin. İki incelik kendini amorti eder: dizini ekleme sırasına göre değil, önem derecesine ya da sayfaya göre sıralayın ve dizin başlığına bir dönüş bağlantısı koyun ki gözden geçiren her maddeden sonra başa dönebilsin. Belge içi bağlantılar, arkalarında ilişki katmanında hiçbir şey olmayan düz konum dizeleri olduğundan, bin satırlık bir dizin bile dosya boyutuna ya da kaydetme süresine neredeyse hiçbir şey eklemez

Aynı sayfa dönüş yolculuğunda ikinci kez ekmeğini çıkarır. Gözden geçirilmiş çalışma kitabı geri geldiğinde kodunuz, değişmiş olabilecek açıklamalar için her sayfayı yeniden taramak yerine dizin satırlarının yanındaki hücrelere yazılmış durum değerlerini okur. Yapılandırılmış durum hücrelerinden oluşan bir sütun temiz ayrıştırılır, serbest metinli notların dağınıklığı ise ayrıştırılmaz

Bozulmayı gerçekten yakalayan bir teslimat öncesi denetim geçişi

Bu API bileşenlerinin hiçbiri bir hedefi doğrulamaz. Sildiğiniz bir sayfaya giden bağlantı, yanlış yazılmış bir intranet ana bilgisayarı, geçen çeyrekte kapatılmış bir dosya paylaşımı: hepsi tek bir mırıltı çıkarmadan kaydedilir. ECMA-376 bir bağlantının nasıl saklanacağını belirtir, bir yere çözüleceğini değil. Dolayısıyla gözden geçirme meta verisi taşıyan bir çalışma kitabı, SaveAs çağrısından hemen önce çalıştırılan kendi kısa denetim aşamanızı hak eder:

Delphi içinde SaveAs çağrısından önce belge içi hedefleri, URL izin listelerini, açıklama sayılarını ve alıcıya göre temizlemeyi denetleyen HotXLS teslimat öncesi denetim geçişinin şeması
SaveAs çağrısından hemen önce dört denetim çalışır ve her biri, kütüphanenin kendisinin asla yükseltmeyeceği bir hatayı yakalar
  • Üretim sırasında yazılan her belge içi konumu toplayın ve ünlem işaretinin önündeki sayfa adının çalışma kitabının sayfa koleksiyonunda hâlâ var olduğunu doğrulayın
  • Dış URL bağlantılarını şema ve ana bilgisayar izin listesine karşı denetleyin. Çıplak file:// ve UNC yolları ortam ayrıntısı sızdırır ve dosya ağınızdan çıktığı anda bozulur
  • Sayfa başına açıklamaları sayın ve üreticinizin yazmayı amaçladığı sayıyla karşılaştırın. Notları ikiye katlayan bir yeniden deneme, gözden geçirenin gelen kutusunda değil burada yüzeye çıkar
  • Alıcı kuruluşun dışındaysa yalnızca iç kullanıma yönelik açıklamaları DeleteInRange ile sıyırın

Çalışma kitaplarını bir veri katmanından kuran ekipler bu aşamayı, veriyi zaten doğrulayan aynı işlem hattı adımına katabilir, böylece meta veri denetimi bedavaya birlikte gelir. Mekanik, veritabanı sorgu sonuçlarını Excel raporlarına aktarma yazısında anlatılanın aynısıdır; yalnızca satırlara değil bağlantılara ve açıklamalara çevrilmiştir

Konum dizelerini elle kuran insanları tökezleten bir tırnak ayrıntısı var. Adında boşluk bulunan bir sayfa, konumun içinde tam olarak formül çubuğunun tırnakladığı gibi tırnaklanmalıdır: Quarterly Totals!A1 değil, 'Quarterly Totals'!A1. HotXLS, formül motorunun sayfalar arası başvurular için kullandığı kuralların aynısını uygular, dolayısıyla bir bağlantı bir çalışma sayfası formülünde çalışıyorsa tırnaklaması burada da çalışır. Ona boşluklu ve tırnaksız bir ad verirseniz, girişte uyarılan aynı sessiz ölü bağlantıyı alırsınız

Açıklamalar ve köprüler, üretilmiş bir çalışma kitabının gözden geçirenlerin ikinci kez bakmadan üzerine iş yaptığı parçalarıdır; hiçbir yeri göstermeyen bir hedefin kimse fark etmeden gerçek zarar vermesinin nedeni tam olarak budur. Doğrulama geçişini bir kez kurun, her çalışma kitabını yayına almadan önce çalıştırın; gözden geçirme akışı yeniden adlandırmalar ve dönüşümler boyunca sağlam kalsın. Hem XLS hem XLSX cepheleri için tam API yüzeyi HotXLS Delphi Bileşeni ürün sayfasında belgelenmiştir