HotXLS, ספריית גיליונות אלקטרוניים נייטיבית עבור Delphi ו-C++Builder, מכיל מנוע חישוב המאפשר לחשב נוסחאות ב-Delphi ללא Excel. מנוע זה פועל דרך Calculate ומתרחב ע"י callback events לפונקציות מותאמות אישית
Calculate: חישוב ביטוי כנגד החוברת הנטענת
Book.Calculate(Expression) מחשב ביטוי שרירותי כנגד החוברת הנטענת ומחזיר Variant. הפונקציה שימושית לבדיקה לפני מסירה — לדוגמה, חישוב סכום טווח לאחר מילוי שורות פירוט ובדיקתו מול הרשומה הראשית. בדוק תמיד VarIsNumeric על התוצאה לפני שימוש, מכיוון שמנוע עלול להחזיר שגיאה כ-Variant error
OnUserFunction ו-OnUserFunctionEx: callback לפונקציות מותאמות
HotXLS מאפשר להגדיר פונקציות מותאמות אישית ע"י חיבור ל-event OnUserFunction. ה-event מקבל שם פונקציה ומערך ארגומנטים, ומחזיר ערך. OnUserFunctionEx מרחיב זאת עם גישה לאובייקט הגיליון, מה שמאפשר לפונקציה לגשת לנתונים מהגיליון עצמו
Book.OnUserFunction := procedure(const FuncName: string;
const Args: array of Variant; var Result: Variant)
begin
if SameText(FuncName, 'MYRATE') then
Result := Args[0] * 0.07
else
Result := Null; // signal unknown function
end;
פונקציות מותאמות אינן עוברות ל-Excel
פונקציה מותאמת שמחושבת ב-HotXLS נשמרת בגיליון כביטוי, ולא כפונקציה רשומה. כאשר Excel פותח את הקובץ, הוא מנסה לחשב את הנוסחה מחדש ומחזיר #NAME? מכיוון שאינו מכיר את שם הפונקציה. הפתרון: חשב את הערכים ב-Delphi ב-Calculate, ואז כתוב את הערכים המחושבים ישירות לתאים לפני שמירה
מצב חישוב בחזית XLS
בחזית XLS, IXLSWorkbook.CalculationMode ו-RecalcOnSave שולטים מתי Excel יחשב מחדש בפתיחה. ב-XLSX, Excel תמיד מחשב מחדש בפתיחה ללא תלות בהגדרות אלה
נוסחאות מערך
SetArrayFormula מגדיר נוסחת מערך על טווח תאים — שקול ל-Ctrl+Shift+Enter ב-Excel. כל הטווח מוחזק כיחידה אחת. בקריאה, תאים בתוך נוסחת מערך מדווחים על הנוסחה המקורית; שינוי תא בודד בתוך הטווח אינו נתמך
HotXLS קומפל לתוך אפליקציית Delphi או C++Builder ללא תלויות חיצוניות; מהדורות ורישוי זמינים בדף HotXLS Component
דוגמאות קוד נוספות
procedure TReportBuilder.HandleUserFunction(Sender: TObject;
const FunctionName: WideString; const Args: Variant;
var Value: Variant; var Handled: Boolean);
begin
if SameText(FunctionName, 'DISCOUNT') then
begin
Value := Args[0] * 0.9; // Args arrives as a Variant array
Handled := True;
end;
end;
// wiring and use
Book.OnUserFunction := HandleUserFunction;
Sheet.Cells[1, 1].Value := 200;
Sheet.Cells[1, 2].Formula := 'DISCOUNT(A1)';
Net := Book.Calculate('DISCOUNT(A1) + SUM(A1:A1)');procedure TReportBuilder.HandleUserFunctionEx(Sender: TObject;
const FunctionName: WideString; const Args: Variant;
const Context: TXLSUserFunctionContext;
var Value: Variant; var Handled: Boolean);
begin
if SameText(FunctionName, 'REGIONRATE') then
begin
// the same formula yields a different rate on each regional sheet
Value := RateForSheet(Context.SheetIndex) * Args[0];
Handled := True;
end;
end;// one array formula spanning A2:A4
Sheet.RCRange[2, 1, 4, 1].SetArrayFormula('A1*{1;2;3}');הערות בדיקה לסביבת ייצור
החלק הזה משלים את המאמר מנקודת מבט של שילוב אמיתי. לפני שמעתיקים את הדוגמה לקוד ייצור, חשוב להגדיר איזה קובץ נכנס לתהליך, איזה רכיב יוצר או קורא אותו, איזה פלט המשתמש אמור לקבל, ואילו ערכים חייבים להישמר ללא שינוי בין Delphi, C++Builder וכלים חיצוניים
בדקו את ההתנהגות עם מסמכים קטנים, קלט פגום ונתונים הדומים לסביבת הלקוח. בעיות של גופנים, עמודים, הצפנה, מטא-נתונים או קידוד מתגלות לרוב רק כאשר יש שמות ארוכים, תווים בינלאומיים, אובייקטים מקוננים וערכים ריקים באותו תרחיש
כאשר התהליך רץ כשירות או כמשימת אצווה, הוסיפו בדיקות לשחרור משאבים, שימוש חוזר ברכיבים, טיפול בחריגות ורישום סיבת הכשל. התוצאה צריכה להיות ברורה: הקובץ נוצר, הקובץ נדחה עם סיבה מובנת, או שניתן להריץ את הפעולה מחדש בבטחה