מאמר טכני

אימות נתונים, AutoFilter וטבלאות ב-HotXLS עבור Delphi

HotXLS, ספריית גיליונות אלקטרוניים נייטיבית עבור Delphi ו-C++Builder, חושפת API לשלושה אלמנטי גיליון שמטפלים בניהול קלט ותצוגה: AutoFilter, כללי אימות נתונים וטבלאות מבניות. לכל אחד יש לפחות מלכודת אחת שכדאי להכיר

AutoFilter: מאחסן הגדרה, לא מסנן שורות

Sheet.AutoFilter ב-XLSX מחזיר את הגדרת ה-AutoFilter של הגיליון — הטווח שעליו הוא מוחל ואת עמודות הסינון המוגדרות. HotXLS קורא וכותב את ההגדרה, אך אינו מחיל אותה: שורות לא יוסתרו בעת שמירה. Excel יחיל את הסינון עם פתיחת הקובץ

מלכודת 0-based בעמודות: AddAutoFilterColumn מקבל column ID בהתבסס 0 יחסית לטווח ה-AutoFilter, לא 1-based יחסית לגיליון. אם ה-AutoFilter מתחיל בעמודה A והתאמן לסנן לפי עמודה C, הפרמטר הוא 2 (לא 3). שגיאת off-by-one כאן מסננת את העמודה הלא-נכונה ללא הודעת שגיאה

כללי אימות נתונים

אימות נתונים ב-XLSX מוחזק ב-Sheet.DataValidations. כל כלל הוא TXLSXDataValidation עם Type (list, whole, decimal, date, textLength), Operator, Formula1 ו-Formula2. ניתן להוסיף כלל ע"י DataValidations.Add ולאכלס את שדותיו. HotXLS שומר את הכלל; Excel מיישם אותו — שמירה אינה מאמתת ערכים קיימים

מלכודת showDropDown: הפוך ממה שנראה

הנכס ShowDropDown של TXLSXDataValidation נראה כמו "הצג רשימה נפתחת", אך לפי מפרט OOXML המשמעות שלו הפוכה: showDropDown = True מסתיר את החץ, ו-showDropDown = False (ברירת מחדל) מציג אותו. אם אתה מגדיר ShowDropDown := True בציפייה לחץ, תקבל את ההפך. HotXLS שומר את הערך כפי שהוא, בהתאם למפרט

טבלאות גיליון: שמות ייחודיים

ב-XLSX, טבלאות מבניות מוחזקות ב-Sheet.Tables. Tables.Add(Name, Ref) מוסיף טבלה חדשה על טווח נתון. שם הטבלה חייב להיות ייחודי בכל החוברת — שתי טבלאות עם אותו שם ייצרו קובץ XLSX לא תקין. HotXLS אינו מאמת ייחודיות בזמן הוספה; ודא ייחודיות בקוד שלך לפני הקריאה

HotXLS קומפל לתוך אפליקציית Delphi או C++Builder ללא תלויות חיצוניות; מהדורות ורישוי זמינים בדף HotXLS Component

דוגמאות קוד נוספות

var
  Book: TXLSXWorkbook;
  Sheet: TXLSXWorksheet;
  R, Visible: Integer;
begin
  Book := TXLSXWorkbook.Create;
  try
    Book.Open('orders.xlsx');
    Sheet := Book.Sheets[0];

    Sheet.SetAutoFilter('A1:E500');
    // Column id 3 = fourth column INSIDE the filter range (0-based offset)
    Sheet.AddAutoFilterColumn(3, xlsxAfOpGreaterOrEqual, '1000');

    Visible := 0;
    for R := 2 to 500 do
      if Sheet.AutoFilterRowVisible(R) then
        Inc(Visible);
    // Visible now matches what Excel will show after opening the file

    Book.SaveAs('orders-filtered.xlsx');
  finally
    Book.Free;
  end;
end;
var
  Idx: Integer;
begin
  Idx := Sheet.AddListValidation('C2:C500', 'New,Approved,Blocked');
  Sheet.DataValidations[Idx].SetPrompt('Status',
    'Pick one of the listed states');
  Sheet.DataValidations[Idx].SetError('Invalid status',
    'Type or paste only listed values', xlsxDvErrStop);
  Sheet.DataValidations[Idx].AllowBlank := False;

  // Quantities: whole numbers, zero or more
  Sheet.AddWholeNumberValidation('D2:D500', xlsxDvOpGreaterOrEqual, '0');
end;
var
  Cols: TStringList;
begin
  Cols := TStringList.Create;
  try
    Cols.CommaText := 'OrderId,Customer,Status,Amount,Owner';
    Sheet.AddTable('Orders', 'A1:E500', Cols);
  finally
    Cols.Free;
  end;
end;