مقال تقني

HotXLS Delphi Component: defined names and cross-sheet formulas في Delphi

تشرح المقالة مخزني الأسماء المختلفين، وقرار scope قبل إنشاء الاسم، وموضع علامة equals، وتأثير نقل الصفوف على المراجع بين الأوراق. كما تميز أسماء _xlnm التي تملكها طبقة الخصائص وحدود الواجهة قبل تثبيت التصميم

الاسم المعرَّف هو تسمية تقوم مقام ثابت، أو نطاق خلايا، أو تعبير صيغة، مخزّنة مرة واحدة في المصنف ومُشار إليها رمزيا في كل مكان تُحتاج فيه اكتب TaxRate في صيغة ويحلّها المحرك إلى ما يحمله تعريف الاسم، سواء كان ذلك الحرفي 0.08 أو النطاق Data!$A$2:$D$100 المرجع عبر الأوراق فكرة عمودية: Data!D2 يصل إلى خلية على ورقة أخرى بتأهيل العنوان باسم ورقة اجمع الاثنين معا وتستطيع ورقة ملخص جمع ورقة تفصيلية عبر اسم لا يذكر أبدا عنوانا حرفيا، وهذا بالضبط ما تريده في مصنف يجمّعه مولّد ويدققه محاسب لاحقا

تعرض HotXLS، مكتبة losLab الأصلية لـDelphi لملفات XLS وXLSX، جدول الأسماء لكلتا الصيغتين بوصول للإنشاء والبحث والحذف، إضافة إلى محرك صيغ يحلّ الأسماء والمراجع عبر الأوراق داخل العملية تحتفظ الصيغتان بتسلسلين هرميين منفصلين للأصناف، والفروقات بين واجهتي الأسماء الخاصتين بهما هي الجزء الذي يوقع الكود المنقول من إحداهما إلى الأخرى

مخزنا أسماء لا يتشاركان واجهة

في جانب XLS، تعيد TXLSWorkbook.GetNames مجموعة IXLSNames التي يكتب تحميلها الزائد Add(Name, RefersTo, Visible) اسما في جدول أسماء BIFF المدخلات الفردية تعود ككائنات IXLSName تحمل Name وRefersTo وRefersToRange المُحلَّل، وطريقة Delete في جانب XLSX، TXLSXWorkbook.DefinedNames مجموعة TXLSXDefinedNames بها Add وFindByName وDeleteByName

اتفاقيات البحث تتباعد بطريقة تظهر أثناء النقل لا وقت الترجمة خاصية Item الافتراضية لمجموعة XLS تقبل Variant، لذا كل من Names[0] وNames['TaxRate'] يُحلَّان مقابلها مجموعة XLSX ليس لديها خاصية افتراضية كهذه؛ تستدعي FindByName('TaxRate')، التي تعيد nil حين يكون الاسم غائبا كود مكتوب لواجهة واحدة يُترجَم مقابل الأخرى بالصدفة فقط، ويميل الفشل إلى الظهور كوصول nil وقت التشغيل لا كخط متعرج أحمر في بيئة التطوير

النطاق هو القرار الأول، لا علم تضيفه لاحقا

الاسم المعرَّف إما بنطاق المصنف، مرئي لصيغ كل ورقة، أو بنطاق الورقة، مرئي فقط لصيغ ورقته المالكة في واجهة XLSX التمييز وسيط اختياري واحد DefinedNames.Add(AName, AFormula) ينشئ اسما على مستوى المصنف، بينما Add(AName, AFormula, ASheetIndex) يربطه بورقة واحدة عند قراءته مرة أخرى، تعيد TXLSXDefinedName.SheetIndex القيمة -1 لنطاق المصنف وفهرس الورقة الذي يبدأ من صفر خلاف ذلك

مخطط للأسماء المعرفة بنطاق المصنف ونطاق الورقة في HotXLS مع معامل النطاق في Delphi وقاعدة تصادم الأسماء المحلية
وسيط النطاق قرار تصميمي: تسكن افتراضات العمل في نطاق المصنف بينما تبقى مساعدات الورقة المفردة في نطاق الورقة، حيث يحل الاسم المحلي أولاً

النطاق يعمل أيضا كسياسة تعارضك، وهذا سبب تسويته قبل كتابة أول اسم Excel يسمح بـTotal محلية لكل ورقة بالإضافة إلى Total على مستوى المصنف، وصيغة على ورقة معينة تحل المحلية أولا المصنفات المولَّدة ينبغي أن تعتمد على ذلك عمدا الافتراضات التجارية التي تستهلكها عدة أوراق، مثل معدلات الضريبة، وأسعار الصرف، وفترة التقرير، تنتمي إلى نطاق المصنف النطاقات المساعدة التي تشير إليها صيغ ورقة واحدة فقط أكثر أمانا بنطاق ورقة، حيث لا شيء يمكن أن يظللها ولا يمكنها أن تظلل شيئا

var
  Book: TXLSXWorkbook;
  Data, Summary: TXLSXWorksheet;
begin
  Book := TXLSXWorkbook.Create;
  try
    Data := Book.Sheets.Add('Data');
    Summary := Book.Sheets.Add('Summary');
    // ... املأ Data!A2:D100 بصفوف التفاصيل ...

    Book.DefinedNames.Add('TaxRate', '0.08');                // نطاق المصنف، ثابت
    Book.DefinedNames.Add('DataBlock', 'Data!$A$2:$D$100');  // نطاق المصنف، نطاق خلايا
    Book.DefinedNames.Add('LocalNote', 'Summary!$B$1', 1);   // بنطاق فهرس الورقة 1 فقط

    // صيغ XLSX لا تأخذ '=' في البداية
    Summary.Cells[2, 2].Formula := 'SUM(Data!D2:D100)*TaxRate';
    Book.SaveAs('model.xlsx');
  finally
    Book.Free;
  end;
end;

الاسم المعرَّف لا يجب أن يشير إلى نطاق TaxRate أعلاه يشير إلى الثابت المجرد 0.08، وتلك أنظف طريقة لنشر افتراض تجاري يظهر مرة واحدة في Name Manager الخاص بـExcel، وتشير إليه كل صيغة رمزيا، وتغيير المعدل في الربع القادم تحرير من سطر واحد للمولّد بدل بحث عبر أربع عشرة سلسلة صيغة مجمَّعة

علامة المساواة التي تنتمي إلى جانب واحد فقط

قناة إدخال الصيغة هي حيث ينكسر الكود المنقول أكثر ما يكون، لأن الواجهتين تختلفان بشأن علامة المساواة خلايا XLS تستقبل الصيغ عبر Value مع = في البداية خلايا XLSX لديها خاصية Formula مخصصة تأخذ التعبير دون البادئة اكتب '=SUM(A1:A10)' في TXLSXCell.Formula وستصبح علامة المساواة جزءا من نص التعبير المخزَّن لا علامة، ولن يتصرف الملف بالطريقة التي تصرفت بها السلسلة نفسها في جانب XLS

مخطط يقابل قنتَي إدخال الصيغ في Delphi داخل HotXLS حيث تتطلب Value في XLS علامة يساوي بادئة وتمنعها Formula في XLSX
يدخل التعبير نفسه عبر Value مع علامة يساوي في جانب XLS وعبر Formula دونها في جانب XLSX — وخلط الاصطلاحين يخزّن العلامة نصاً
var
  Book: IXLSWorkbook;   // معدود بالواجهة: لا تستدعِ Free
  Names: IXLSNames;
begin
  Book := TXLSWorkbook.Create;
  // افترض أن ورقة اسمها 'Data' تحمل بالفعل صفوف التفاصيل
  Names := Book.GetNames;
  Names.Add('TaxRate', '0.08');
  Names.Add('Helper', 'Data!$A$2:$A$100', False);  // False = مخفي عن Name Manager

  // صيغ XLS تمر عبر Value، مع بادئة '='
  Book.Sheets[1].Cells.Item[2, 2].Value := '=SUM(Data!A2:A100)*TaxRate';
  Book.SaveAs('model.xls');
end;

ذلك المقتطف يُظهر خصوصيتين أخريين في جانب XLS مجموعة الأوراق تبدأ من واحد، لذا Sheets[1] هي الورقة الأولى، مقابل Sheets[0] التي تبدأ من صفر في XLSX ووسيط Add الثالث ينشئ اسما مخفيا: موجود في الملف وقابل للاستخدام في الصيغ، ومع ذلك غير مرئي في Name Manager الخاص بـExcel الأسماء المخفية هي الأداة الصحيحة لأعمال السباكة الداخلية للمولّد التي يجب ألا يحررها المستخدمون النهائيون أو يحذفوها بالخطأ أبدا

المراجع عبر الأوراق، وما يحدث حين تتحرك الصفوف

كلا محركي الصيغ يقبلان الصيغة القياسية عبر الأوراق أسماء الأوراق البسيطة تؤهّل مباشرة كـData!A1؛ اسم به مسافات أو علامات ترقيم يحتاج علامات اقتباس مفردة، كما في 'Sheet With Space'!A1 داخل نص RefersTo لاسم، اعتمد على المراجع المطلقة مثل Data!$A$2:$D$100 تقريبا في كل مرة المرجع النسبي داخل اسم معرَّف يُحلّ نسبيا إلى الخلية التي تستخدمه، وهذه ميزة متعمدة في Excel ومصدر موثوق للارتباك حين تُطلَق بالخطأ

التعديلات البنيوية هي حيث تثبت محاسبة الأوراق المتقاطعة جدواها، وجانب XLSX يحافظ على اتساق الأسماء عبرها InsertRows وDeleteRows ينقلان نطاقات الأسماء المعرَّفة مع الخلايا والدمج والروابط التشعبية ومراسي المخططات، لذا اسم يشير إلى Data!$A$2:$D$100 لا يزال يغطي كتلة البيانات بعد أن يفتح المولّد فجوة فوقها الصيغ تأتي مع تحفظ موثق واحد: إدخال الصفوف يعدّل فقط المراجع التي تستهدف الورقة قيد التحرير صيغة Summary تشير إلى Data!D2:D100 تُعاد كتابتها حين تدخل صفوف إلى Data، وهذه هي الحالة التي تريدها عادة تحقق من ذلك بدل افتراضه، لأن المحرك سيخبرك برخص

// محرك الحساب يحلّ الأسماء والمراجع عبر الأوراق داخل العملية
V := Book.Calculate('SUM(Data!D2:D100)*TaxRate');
if VarIsNumeric(V) then
  Log('net total checks out: ' + FloatToStr(V));

Calculate يحسب تعبيرا اعتباطيا مقابل حالة المصنف الحالية دون حفظ أي شيء، ما يجعله بدائية التأكيد الطبيعية لاختبارات المولّد احسب المجموع المتوقع من بيانات المصدر في Pascal، واحسب صيغة المصنف نفسها، وقارن بينهما مقالة محرك الصيغ تغطي ما يحسبه المحرك، ومتى، وكيف توسّعه بدوال مخصصة

أسماء _xlnm التي تملكها طبقة الخصائص

افتح جدول أسماء ملف مولَّد في مفتش منخفض المستوى وستجد مدخلات لم تكتبها أبدا: _xlnm.Print_Area و_xlnm.Print_Titles وأقاربها هذه هي الطريقة التي يخزّن بها OOXML (ECMA-376 / ISO 29500) مناطق الطباعة وصفوف العناوين المتكررة، كأسماء معرَّفة بمعرّفات محجوزة تدير HotXLS إياها عبر خصائص ورقة عمل مخصصة، لذا ضبط PrintArea أو PrintTitleRows يكتب مدخل _xlnm.* المقابل نيابة عنك

الفخ هو الوصول إلى فضاء الأسماء المحجوز ذاك يدويا أضف مدخل _xlnm.Print_Area عبر DefinedNames.Add بينما تضبط أيضا خاصية PrintArea وسيحمل المصنف تعريفين متعارضين لاسم محجوز واحد، حالة يحلها Excel بطرق لا ينبغي لأي منتج الاعتماد عليها عامل كل معرّف يبدأ بـ_xlnm. على أنه ينتمي إلى طبقة الخصائص لفحص إعداد الطباعة، اقرأ الخصائص، لا جدول الأسماء مقالة الحماية وإعداد الصفحة تغطي خصائص منطقة الطباعة في سياقها

حدان يستحقان المعرفة قبل الالتزام بتصميم

الأسماء المعرَّفة لا ترافق الرحلة عبر جسر التحويل السهل من XLS إلى XLSX SaveXLSWorkbookAsXLSX ينسخ محتوى الخلايا والتنسيق الأساسي، وجدول الأسماء ليس في قائمة النسخ الموثقة الخاصة به، لذا مصنف اعتمد على أسمائه يفقدها في العبور أعد إنشاء الأسماء عبر DefinedNames.Add بعد التحويل تلك الخطوة أقل عبئا مما تبدو، لأنها تمنحك لحظة لتوحيد نطاقاتها بدل نقل أيا كان ما حمله ملف XLS مصادفة

الحد الآخر هو الانحراف بين نصوص الصيغ وأسماء الأوراق Excel يعيد كتابة مراجع الأوراق داخل الصيغ والأسماء أثناء إعادة تسمية تفاعلية، لذا الملفات التي يحررها مستخدم في Excel تبقى متسقة تلقائيا التعرض في جانب المولّد: حين يجمّع كود Pascal سلاسل صيغ من حرف اسم ورقة، فإن إعادة تسمية الورقة في مكان واحد ونسيان المكان الآخر ينتج مرجعا إلى ورقة لم تعد موجودة أبقِ اسم الورقة في ثابت Delphi واحد وغذِّه إلى كل من Sheets.Add وتجميع صيغتك، ولن يختلف الاثنان أبدا هذا هو نفس الحدس الذي يدافع عن تسمية خلايا خرج تقرير بدل ترميز العناوين مباشرة: قالب خليته الإجمالية مسمّاة يستمر في العمل بعد أن يدخل مصمم ثلاثة صفوف فوقها، بينما مولّد يكتب إلى B17 حرفي يضع رقمه بصمت في المكان الخطأ مقالة توليد تقارير القوالب تبني بالضبط على هذا النمط

الواجهة البرمجية الكاملة للأسماء المعرَّفة لكلتا الصيغتين، إضافة إلى مرجع محرك الصيغ، تأتي مع HotXLS Delphi Component