أعد تسمية ورقة من "Summary" إلى "Overview" في مصنف مولَّد، وكل رابط تشعبي داخلي كان يشير إلى Summary!A1 يتوقف عن الإشارة إلى أي مكان. لا استثناء عند الحفظ، ولا عند الفتح. الرابط لا يزال يُعرَض، ولا يزال يبدو قابلًا للنقر، ويُحل بهدوء إلى لا شيء. نفس نوع الكسر يظهر بعد تحويل حفظ باسم، أو رحلة ذهاب وإياب بين .xls و.xlsx، عندما يهبط تعليق بعيدًا عمودًا واحدًا أو يفقد رابط نسبي هدفه. كلتا الميزتين تحملان حالة مراجعة يتصرف بناءً عليها أشخاص حقيقيون، فعندما تنكسران يكون الفشل غير مرئي حتى ينقر مراجع ولا يحدث شيء
هذا هو السبب العملي الذي يجعل التعليقات والروابط التشعبية تستحق عناية أكثر مما يوحي به مظهرها التجميلي. يمنح HotXLS كود Delphi وC++Builder وصولًا مباشرًا بالكتابة إلى كليهما، في XLS وXLSX، دون أي أتمتة لـExcel في الحلقة. الوجه الآخر لتلك السيطرة هو المسؤولية: تكتب المكتبة بالضبط الأهداف التي تسلّمها إياها ولا تتحقق من صحة أي منها، فإبقاء سير عمل المراجعة سليمًا هو مهمة كودك أنت، لا مهمة Excel
تعليقات الخلايا كسجلات مراجعة مكتوبة آليًا
في نموذج صنف XLSX، التعليق كائن على مستوى ورقة العمل: يعرف صفه، وعموده، ومؤلفه، وجسم نصه. حقل المؤلف يستحق مكانه. عندما يمر مصنف أنشأه كودك عبر سلسلة مراجعة، فإن أول سؤال يطرحه المدقق هو من كتب ملاحظة معينة، وملاحظة تُركت دون مؤلف تجيب عن ذلك السؤال بفراغ. اختم التعليقات المولَّدة بهوية خدمة حتى لا يكون المصدر غامضًا أبدًا
var
Book: TXLSXWorkbook;
Sheet: TXLSXWorksheet;
Note: TXLSXComment;
begin
Book := TXLSXWorkbook.Create;
try
Book.Open('reconciliation.xlsx');
Sheet := Book.Sheets[0];
// ملاحظة موقّعة على الرقم المعدَّل
Sheet.AddComment(14, 4, 'Manual adjustment: late FX rate, see ticket FIN-2214',
'recon-service');
// تحديث ملاحظة موجودة بدلًا من تكديس ملاحظة ثانية
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 يحمل وزنًا أكبر مما يبدو عليه. مهمة دفعية تعيد المحاولة بعد فشل عابر ستستدعي بسعادة AddComment مرة ثانية على خلية علّقت عليها بالفعل، وتنتهي الخلية بملاحظتين متكدستين لم يطلبهما أحد. افحص بـFindAt أولًا، وحدّث الكائن الذي تعيده. مجموعة Comments تكشف أيضًا DeleteAt وDeleteInRange. تلك النسخة الخاصة بالنطاق هي ما تلجأ إليه عندما تطهّر مصنفًا قبل مغادرته المبنى: مسح تعليقات ضمان الجودة الداخلية من منطقة كاملة استدعاء واحد بدلًا من حلقة مكتوبة يدويًا عبر الخلايا
عناوين URL الخارجية والقفزات داخل المصنف واجهتان مختلفتان
تحفظ OOXML نوعي الروابط في مكانين مختلفين. عنوان URL خارجي يصبح إدخال علاقة في جزء .rels الخاص بالورقة، والخلية تشير إلى العلاقة بمعرّفها. أما القفزة الداخلية فلا تلمس طبقة العلاقات على الإطلاق؛ إنها سلسلة موقع نصية عادية مثل Summary!A1 مخزَّنة مباشرة على الرابط. يبقي HotXLS ذلك التمييز مرئيًا في الواجهة بدلًا من إثقال طريقة واحدة بمعانٍ متعددة، وهذا يعني أنك تختار الاستدعاء الصحيح بمعرفة أين يعيش الهدف:
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');
على كائن TXLSXHyperlink الناتج، Url وLocation متنافيتان، وIsInternal تخبرك أيهما مُعبَّأة. تلك العلامة هي ما تفحصه عندما تجرد الروابط في مصنف مفتوح وتحتاج إلى معاملة "يغادر الملف" و"يبقى داخل الملف" بقواعد مختلفة: مضيف خارجي قد يواجه قائمة سماح بينما هدف داخلي لا يحتاج إلا تسمية ورقة موجودة فعلًا. الروابط الداخلية لا تحمل خلفها أي أجزاء علاقة، وهذا أيضًا ما يجعل إعادة كتابتها بالجملة أرخص
الكسر من الافتتاحية يعيش بالكامل في الجهة الداخلية، وهو يتبع حقيقة واحدة: سلسلة الموقع ليست مرجعًا مُحلَّلًا. يكتب HotXLS النص بالضبط كما سلّمته إياه، ولا شيء يعيد توجيه ذلك النص عندما تُعاد تسمية ورقة لاحقًا. دفاعان يصمدان عمليًا. الأول انضباط بشأن الترتيب: أعد تسمية كل ورقة قبل توليد رابط واحد، ثم عامل أسماء الأوراق كمعرّفات مجمَّدة. الثاني أمتن وينجو من إعادة التسمية التي تحدث لاحقًا. وجّه الرابط إلى اسم معرَّف على مستوى المصنف بدلًا من عنوان Sheet!Cell خام، لأن Excel يعيد كتابة تعريف الاسم عندما تتغير الورقة الأساسية، فيركب الرابط تلقائيًا. هذا النهج الثاني يقترن طبيعيًا بالتقنيات في الأسماء المعرَّفة والصيغ بين الأوراق في HotXLS
جهة XLS: نفس المفاهيم، سباكة أقدم
واجهة BIFF8 تعلّق التعليقات بالنطاقات بدلًا من مجموعة على مستوى ورقة العمل. تستدعي AddComment على IXLSRange وتستعيد TXLSComment؛ خاصية Comment الخاصة بالنطاق تقرأ ملاحظة موجودة، وClearComments تمحوها. الحافة الحادة هنا موضعية. TXLSComment لا تكشف علنًا صفها وعمودها الخاصين، فالحلقة الطبيعية، "اجتز كل تعليق وأبلغ عن مكانه"، تعمل بالعكس ضد الواجهة. عليك أن تبدأ من الخلايا. إما أن تشغّل التدقيق من قائمة العناوين التي علّقت عليها، أو تحتفظ بسجل مواضع خاص بك أثناء الكتابة، لأن كائن التعليق لن يخبرك لاحقًا أين يعيش
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; // اجعل الملاحظة تنبثق مفتوحة من أول مشاهدة
Sheet.AddHyperlink(7, 2, 'https://intranet.example.com/signoff/4821',
'Sign-off form', 'Opens the controller queue');
Book.SaveAs('review.xls');
end;
ضبط Visible على True هو الطريقة القديمة لجعل ملاحظة يستحيل إغفالها: يبقى المربع الأصفر مفتوحًا على الورقة بدلًا من انتظار التمرير فوقها. TXLSComment تذهب خطوة أبعد من نظيرتها في XLSX بكشف TextRuns، فيمكن لملاحظة واحدة أن تحمل تحذيرًا بخط عريض إلى جانب شرح عادي، تنسيق لا تكشفه واجهة تعليقات XLSX بنفس الطريقة. الروابط التشعبية في هذه الجهة تصل عبر ثلاث حمولات زائدة متدرجة (العنوان وحده، ثم مع نص عرض، ثم مع تلميح شاشة) وتُقرأ مجددًا عبر مجموعة HyperLinks الخاصة بورقة العمل، حيث يعرض كل رابط Address وSubAddress وDisplayText وScreenTip
ورقة فهرس مراجعة تتفوق على ملاحظات متناثرة
بعد نحو عشر إضافات توضيحية، يتوقف التمرير للقراءة بهدوء عن التوسع. تتكدس الملاحظات على أوراق لا يفتحها مراجع أبدًا، والملاحظات الأهم هي بالضبط الأسهل تفويتًا. البنية التي أثبتت جدارتها هي ورقة فهرس مولَّدة: صف واحد لكل موقع مُعلَّق عليه، يسرد اسم ورقته، وعنوان خليته، ومؤلفه، ومقتطفًا قصيرًا من الملاحظة. العمود الأخير يحمل رابطًا تشعبيًا داخليًا مبنيًا بـAddHyperlinkToCell يقفز مباشرة إلى الخلية المُعلَّق عليها. الآن يقرأ المراجع قائمة للأسفل بدلًا من البحث عبر شبكة، وعدد صفوف ذلك الفهرس يخدم في آن واحد كجرد تعليقاتك لمرحلة التدقيق أدناه
الفهرس رخيص البناء لأن مولِّدك يعرف بالفعل كل موضع لمسه. ألحق مجموعة (ورقة، صف، عمود، مؤلف، ملخص) بقائمة أثناء كتابة كل تعليق، ثم أصدر ورقة الفهرس أخيرًا حتى يكون عدد صفوفها نهائيًا قبل الحفظ. تحسينان يستحقان العناء: رتّب الفهرس حسب الخطورة أو حسب الورقة بدلًا من تسلسل الإدراج، وضع رابط عودة في ترويسة الفهرس حتى يستطيع المراجع الارتداد إلى الأعلى بعد كل عنصر. ولأن الروابط الداخلية سلاسل موقع نصية عادية دون أي شيء في طبقة العلاقات خلفها، حتى فهرس بألف صف لا يضيف تقريبًا شيئًا يُذكر إلى حجم الملف أو وقت الحفظ
تلك الورقة نفسها تسدد ثمنها مجددًا في رحلة العودة. عندما يعود المصنف المُراجَع، يقرأ كودك قيم حالة كُتبت في خلايا بجانب صفوف الفهرس بدلًا من إعادة مسح كل ورقة بحثًا عن تعليقات ربما تغيّرت. عمود من خلايا حالة منظَّمة يُحلَّل بنظافة؛ تناثر من ملاحظات نصية حرة لا يُحلَّل كذلك
مرحلة تدقيق قبل التسليم تلتقط الكسر فعليًا
لا شيء من هذه الواجهات يتحقق من صحة هدف. رابط إلى ورقة حذفتها، مضيف إنترانت مكتوب خطأ، مشاركة ملفات أُلغي تشغيلها الربع الماضي: كل هذه تُحفظ دون أي همسة. تحدد ECMA-376 كيفية تخزين رابط، لا أنه يُحل إلى شيء ما. لذا فإن مصنفًا يحمل بيانات وصفية للمراجعة يستحق مرحلة تدقيق قصيرة خاصة به، تُشغَّل قبل SaveAs مباشرة:
- اجمع كل موقع داخلي كُتب أثناء التوليد وتأكد أن اسم الورقة قبل علامة التعجب لا يزال موجودًا في مجموعة أوراق المصنف
- افحص عناوين URL الخارجية مقابل قائمة سماح من المخططات والمضيفين. مسارات
file://وUNC العارية تسرّب تفاصيل بيئة وتنكسر في اللحظة التي يغادر فيها الملف شبكتك - عدّ التعليقات لكل ورقة وقارنها بما نوى مولِّدك كتابته. إعادة محاولة ضاعفت الملاحظات تظهر هنا بدلًا من صندوق وارد المراجع
- اشطب الإضافات التوضيحية الداخلية فقط بـ
DeleteInRangeكلما كان المستلم خارج المؤسسة
الفرق التي تبني مصنفاتها من طبقة بيانات يمكنها طي هذه المرحلة داخل خطوة خط الأنابيب نفسها التي تتحقق أصلًا من صحة البيانات، فيركب فحص البيانات الوصفية مجانًا. الآليات هي نفسها الموصوفة في تصدير نتائج استعلامات قاعدة البيانات إلى تقارير Excel، موجَّهة نحو الروابط والتعليقات بدلًا من الصفوف
تفصيل اقتباس واحد يوقع الناس عندما يبنون سلاسل مواقع يدويًا. ورقة يحتوي اسمها على مسافة يجب اقتباسها داخل الموقع، تمامًا كما يقتبسها شريط الصيغة: 'Quarterly Totals'!A1، لا Quarterly Totals!A1. يطبّق HotXLS نفس القواعد التي يستخدمها محرك الصيغ للمراجع بين الأوراق، فإذا كان رابط يعمل في صيغة ورقة عمل، فإن اقتباسه سيعمل هنا أيضًا. سلّمه اسمًا غير مقتبس بمسافة وستحصل على نفس الرابط الميت الصامت الذي حذرت منه الافتتاحية
التعليقات والروابط التشعبية هي الأجزاء من مصنف مولَّد التي يتصرف المراجعون بناءً عليها دون نظرة ثانية، وهذا بالضبط سبب أن هدفًا يشير إلى لا شيء يسبب ضررًا حقيقيًا قبل أن ينتبه أحد. ابنِ مرحلة التحقق مرة واحدة، وشغّلها على كل مصنف قبل شحنه، ويبقى سير عمل المراجعة سليمًا عبر إعادات التسمية والتحويلات. سطح API الكامل لكلتا واجهتَي XLS وXLSX موثَّق على صفحة منتج HotXLS Delphi Component