Копия викизеркало

Это зеркало вики с pascal.chat. Правка, история и вход — там.

FPSpreadsheet/ru

Deutsch · English · Español · Français · Polski · Русский

FpSpreadsheet библиотека предоставляет удобный способ создания и чтения табличных документов в различных форматах. Библиотека написана на очень гибкой основе, и поэтому её можно легко расширять поддержкой любого количества форматов.

Скриншот демонстрационной программы spready, предоставляемой с fpspreadsheet, показывающим файл XLS:

fpsgrid.png

Документация

Эта страница вики включает последнюю версию FPSpreadsheet, доступную через subversion. Пожалуйста, см. раздел Стабильные версии для [получения] документации по стабильной версии, которую вы можете скачать.

Документация по API

Ссылка на API

Файл справки в формате CHM можно найти в папке установки FPSpreadsheet docs. Если вы еще не установили пакет, тогда следуйте сюда https://sourceforge.net/p/lazarus-ccr/svn/HEAD/tree/components/fpspreadsheet/docs

Второй файл CHM, доступный в папке docs , fpspreadsheet-wiki.chm , представляет собой снимок связанных с FPSpreadsheet страниц вики, объединенных в один файл справки.

Основы

Наименьшими объектами в электронной таблице являются «ячейки», содержащие данные. Ячейки могут содержать различные типы данных, такие как строки, числа, даты, время, логические значения или формулы. Кроме того, ячейки могут содержать информацию о форматировании, то есть стиль шрифта, цвет фона, выравнивание текста и т.д.

Ячейки расположены в сетке, называемой «рабочей таблицей», или «электронной таблицей», состоящей из «строк» и «столбцов». Каждая ячейка имеет уникальный адрес, заданный индексом строки и столбца.

Рабочие листы связаны вместе, формируя «книгу», которая представляет собой документ электронной таблицы приложения. В книге также хранится информация, необходимая для всех листов, то есть список шрифтов, списки сотовых и числовых форматов и т.д.

FPSpreadsheet следует этой же структуре - существует TCell, TsWorksheet и TsWorkbook.

Рабочая книга

Класс TsWorkbook является основным классом, видимым для пользователя. Он предоставляет методы для чтения данных и записи в файлы. Универсальная структура библиотеки обеспечивает доступ к различным популярным форматам файлов, таким как Excel .xls или .xlsx , или OpenOffice/LibreOffice .ods.

Формат файла определяется типом TsSpreadsheetFormat, определенным в модуле fpstypes

pascal
type
      TsSpreadsheetFormat = (sfExcel2, sfExcel5, sfExcel8, sfExcelXML, sfOOXML, 
        sfOpenDocument, sfCSV, sfHTML, sfWikiTable_Pipes, sfWikiTable_WikiMedia, sfUser);

где

При применении fpspreadsheet первая задача - создать экземпляр рабочей книги:

pascal
var
      MyWorkbook: TsWorkbook;
    begin
      MyWorkbook := TsWorkbook.Create;
      ...

Чтение файлов электронных таблиц выполняется (среди прочего) методами рабочей книги

Читает файл с заданным именем и автоматически определяет правильный формат файла.

Читает файл, но предполагает, что формат файла соответствует AFormat.

Для сохранения файла можно использовать следующие методы работы с книгой:

Записывает книгу в данный файл с использованием заданного формата электронной таблицы. Если файл уже существует, он автоматически перезаписывается, если AOverwriteExisting - true:

так же, но формат файла определяется из предоставленного расширения файла (в случае Excel больше xls используется последняя версия, sfExcel8).

После вызова этих методов полезно посмотреть на свойство рабочей книги ErrorMsg, в котором собраны сообщения из-за ошибок или предупреждений, которые могли возникнуть во время чтения/записи. Это свойство возвращает многострочную строку, которая лучше всего отображается в компоненте memo; если все в порядке, это пустая строка.

Примечание. FPSpreadsheets предоставляет специализированные блоки для чтения и записи в каждый формат файла. Эти блоки недоступны автоматически, вы должны явно добавить их в предложение uses. FPSpreadsheet будет жаловаться на «неподдерживаемый формат файла», если запрошенный читатель/писатель не найден. Ниже приведен список названий устройств:

Рабочий лист

В книге содержится список экземпляров TsWorksheet. Они соответствуют вкладкам, которые вы видите в Excel или Open/LibreOffice. При чтении файла электронной таблицы рабочие листы создаются автоматически в соответствии с содержимым файла. Когда электронная таблица создается вручную для хранения в файле, рабочий лист должен быть создан путем «добавления» в рабочую книгу:

pascal
var
      MyWorkbook: TsWorkbook;
      MyWorksheet: TsWorksheet;
    begin
      MyWorkbook := TsWorkbook.Create;
      MyWorksheet := MyWorkbook.AddWorksheet('My_Table');  
        // 'My_Table' - это «имя» рабочего листа
      ...

Доступ к уже имеющимся рабочим листам можно получить с помощью методов TsWorkbook

Количество уже существующих рабочих листов можно запросить, вызвав GetWorksheetCount.

Ячейка

Рабочий лист, наконец, дает доступ к ячейкам. Недавно созданный рабочий лист, как в приведенном выше примере, пуст и не содержит никаких ячеек. Клетки добавляются путем присвоения им данных или атрибутов одним из методов WriteXXXX рабочего листа. Как уже упоминалось, ячейка адресуется индексом строки и столбца, к которой она принадлежит. Как обычно, индексы строк и столбцов начинаются с 0. Поэтому ячейка «A1» относится к строке 0 и столбцу 0. Следует отметить, что индекс строки и столбца всегда указывается в этом порядке, это отличается от соглашения TStringGrid. В следующем примере создается ячейка по адресу A1 и помещается в нее число 1.0.

pascal
var
      MyWorkbook: TsWorkbook;
      MyWorksheet: TsWorksheet;
    begin
      MyWorkbook := TsWorkbook.Create;
      MyWorksheet := MyWorkbook.AddWorksheet('My_Table');
      MyWorksheet.WriteNumber(0, 0, 1.0);  // "A1" имеет строку = 0 и столбец = 0
      ...

Также можно напрямую обращаться к ячейкам с помощью методов FindCell(ARow, ACol) или GetCell(ARow, ACol) рабочей книги. Обе функции существуют также в перегруженной версии, к которой адрес ячейки может быть передан в нотации Excel: FindCell(ACellStr: String) или GetCell(ACellStr: String). Имейте в виду, что эти функции возвращают указатель pointer к данным ячейки (тип PCell). Не забудьте разыменовать указатели! Разница между FindCell и GetCell заключается в том, что первая возвращает nil, если ячейка еще не существует, а вторая создает пустую ячейки в этом случае.

pascal
if MyWorksheet.FindCell('A1') = nil then
      WriteLn('Ячейка A1 не существует.');
Основной тип TCell record

Это объявление типа данных ячейки:

pascal
type
      TCell = record
        { Location of the cell }
        Worksheet: TsWorksheet;
        Col: Cardinal; // zero-based
        Row: Cardinal; // zero-based
    
        { Index of format record }
        FormatIndex: Integer;
    
        { Status flags }
        Flags: TsCellFlags;        // (cfHasComment, cfMerged, cfHyperlink, ...)
    
        { Cell content }
        UTF8StringValue: String;   // строки не могут быть частью варианта записи 
        case ContentType: TCellContentType of  // должно быть в конце объявления
          cctEmpty      : ();      // не имеет данных вообще
          cctFormula    : ();      // UTF8StringValue находится вне варианта записи
          cctNumber     : (Numbervalue: Double);
          cctUTF8String : ();      // FormulaValue находится вне варианта записи 
          cctDateTime   : (DateTimevalue: TDateTime);
          cctBool       : (BoolValue: boolean);
          cctError      : (ErrorValue: TsErrorValue);
      end;
      PCell = ^TCell;

Поле ContentType указывает, какой тип данных хранится в ячейке:

pascal
type
      TCellContentType = (cctEmpty, cctFormula, cctNumber, cctUTF8String, cctDateTime, cctBool, cctError);

Согласно этому полю соответствующие данные можно найти в полях

Из-за использования варианта записи большинство из этих значений перекрываются, то есть модификация NumberValue влияет также на другие значения. Поэтому всегда обращайте внимание на ContentType при непосредственном доступе к записи TCell (описанные ниже методы рабочего листа рассматривают это автоматически).

Поле Flags указывает, связаны ли дополнительные данные с ячейкой, которые не включены в запись ячейки, как правило, для сохранения памяти:

pascal
type 
      TsCellFlag = (cfHasComment, cfHyperlink, cfMerged, cfHasFormula, cf3dFormula);
      TsCellFlags = set of TsCellFlag;

Note-icon.png

Примечание: После вычисления формулы или после прочтения файла ContentType ячейки формулы преобразуется в формулу результата. Тогда наличие формулы может быть обнаружено только путем вызова функции HasFormula(cell) для запрашиваемой ячейки (cell: PCell) в модуле fpsUtils ; эта функция проверяет наличие элемента cfHasFormula в флажках ячейки.

Как добавлять и считывать данные в/из ячейки

Добавление значений в ячейку наиболее легко сопровождается использованием одного из методов WriteXXXX рабочего листа. Наиболее важными являются:

pascal
type
      TsWorksheet = class
        ...
        { Запись денежных значений }
        function WriteCurrency(ARow, ACol: Cardinal; AValue: Double;
          ANumFormat: TsNumberFormat = nfCurrency; ADecimals: Integer = 2;
          ACurrencySymbol: String = '?'; APosCurrFormat: Integer = -1;
          ANegCurrFormat: Integer = -1): PCell; overload;
        procedure WriteCurrency(ACell: PCell; AValue: Double;
          ANumFormat: TsNumberFormat = nfCurrency; ADecimals: Integer = -1;
          ACurrencySymbol: String = '?'; APosCurrFormat: Integer = -1;
          ANegCurrFormat: Integer = -1); overload;
        function WriteCurrency(ARow, ACol: Cardinal; AValue: Double;
          ANumFormat: TsNumberFormat; ANumFormatString: String): PCell; overload;
        procedure WriteCurrency(ACell: PCell; AValue: Double;
          ANumFormat: TsNumberFormat; ANumFormatString: String); overload;
    
        {Запись значений дата/время }
        function WriteDateTime(ARow, ACol: Cardinal; AValue: TDateTime): PCell; overload;
        procedure WriteDateTime(ACell: PCell; AValue: TDateTime); overload;
        function WriteDateTime(ARow, ACol: Cardinal; AValue: TDateTime;
          ANumFormat: TsNumberFormat; ANumFormatStr: String = ''): PCell; overload;
        procedure WriteDateTime(ACell: PCell; AValue: TDateTime;
          ANumFormat: TsNumberFormat; ANumFormatStr: String = ''); overload;
        function WriteDateTime(ARow, ACol: Cardinal; AValue: TDateTime;
          ANumFormatStr: String): PCell; overload;
        procedure WriteDateTime(ACell: PCell; AValue: TDateTime;
          ANumFormatStr: String); overload;
    
        { Запись числовых значений } 
        function WriteNumber(ARow, ACol: Cardinal; ANumber: double): PCell; overload;
        procedure WriteNumber(ACell: PCell; ANumber: Double); overload;
        function WriteNumber(ARow, ACol: Cardinal; ANumber: double;
          ANumFormat: TsNumberFormat; ADecimals: Byte = 2): PCell; overload;
        procedure WriteNumber(ACell: PCell; ANumber: Double;
          ANumFormat: TsNumberFormat; ADecimals: Byte = 2); overload;
        function WriteNumber(ARow, ACol: Cardinal; ANumber: double;
          ANumFormat: TsNumberFormat; ANumFormatString: String): PCell; overload;
        procedure WriteNumber(ACell: PCell; ANumber: Double;
          ANumFormat: TsNumberFormat; ANumFormatString: String); overload;
    
        { Запись строковых значений }
        function WriteText(ARow, ACol: Cardinal; AText: ansistring;
          ARichTextParams: TsRichTextParams = nil): PCell; overload;
        procedure WriteText(ACell: PCell; AText: String;
          ARichTextparams: TsRichTextParams = nil); overload;
    
        // старые методы строк «WriteUTF8Text» сейчас устарели
        ...

Некоторые из этих методов существуют в перегруженных версиях, в которых параметры форматирования ячейки могут быть добавлены вместе со значением ячейки. Соответственно, для записи также существует несколько методов worksheet для чтения значений ячеек:

pascal
type
      TsWorksheet = class
        ...
        { Чтение содержимого ячейки как строки }
        function  ReadAsText(ARow, ACol: Cardinal): string; overload;
        function  ReadAsText(ACell: PCell): string; overload;
        function  ReadAsText(ACell: PCell; AFormatSettings: TFormatSettings): string; overload;
    
        { Чтение содержимого ячейки как числа }
        function  ReadAsNumber(ARow, ACol: Cardinal): Double; overload;
        function  ReadAsNumber(ACell: PCell): Double; overload;
        function  ReadNumericValue(ACell: PCell; out AValue: Double): Boolean;
    
        { Чтение содержимого ячейки как значения дата/время }
        function  ReadAsDateTime(ARow, ACol: Cardinal; out AResult: TDateTime): Boolean; overload;
        function  ReadAsDateTime(ACell: PCell; out AResult: TDateTime): Boolean; overload;
        ...
Индексирование формата ячейки

FormatIndex является индексом записи формата ячейки cell format record. Он описывает атрибуты форматирования ячейки. Эти записи собираются по внутреннему списку рабочей книги и определяются следующим образом:

pascal
type
      TsCellFormat = record
        FontIndex: Integer;
        TextRotation: TsTextRotation;
        HorAlignment: TsHorAlignment;
        VertAlignment: TsVertAlignment;
        Border: TsCellBorders;
        BorderStyles: TsCellBorderStyles;
        Background: TsFillPattern;
        NumberFormatIndex: Integer;
        NumberFormat: TsNumberFormat;
        NumberFormatStr: String;
        BiDiMode: TsBiDiMode;           // bdDefault, bdLTR {left-to-right}, bdRTL {right-to-left)
        Protection: TsCellProtection;   // cpLockCell, cpHideFormulas
        UsedFormattingFields: TsUsedFormattingFields;
          //uffTextRotation, uffFont, uffBold, uffBorder, uffBackground, uffNumberFormat, uffWordWrap, uffHorAlign, uffVertAlign, uffBiDi
      end;

Для указания формата для данной ячейки вызывается соответствующий метод рабочего листа WriteXXXX, для получения вызова формата ReadXXXX. Эти методы обычно получают указатель на ячейку в качестве параметра, но также есть перегруженные версии, которые принимают индекс строки и столбца. Более того, стили форматирования также могут быть применены непосредственно к ячейке с помощью вспомогательного средства записи, реализованного в модуле fpsCell.

См. форматирование ячейки ниже для [получения] более подробного описания.

Столбцы и строки

Записи столбцов и строк добавляются для каждого столбца и строки с размером, отличным от значения по умолчанию:

pascal
type
      TCol = record
        Col: Cardinal;
        Width: Single;
        ColWidthType: TsColWidthType;     // = (cwtDefault, cwtCustom)
        FormatIndex: Integer;
      end;
      PCol = ^TCol;
    
      TRow = record
        Row: Cardinal;
        Height: Single;
        RowHeightType: TsRowHeightType;   // = (rhtDefault, rhtCustom, rhtAuto)
        FormatIndex: Integer;
      end;
      PRow = ^TRow;

[Свойства] Column widths и row heights могут быть указаны в различных единицах, определенных типом TsSizeUnits = (suChars, suLines, suMillimeters, suCentimeters, suPoints, suInches). suChars относится к счету символов 0, вписывающихся в ширину столбца, - таким образом Excel определяет ширину столбца. suLines - количество линий, вписывающихся в высоту строки. Оба устройства основаны на размере символа шрифта по умолчанию для книги. Другие единицы - условные физические единицы длины (1 см = 10 мм, 1 дюйм = 25,4 мм = 72 пт). Принимаются дробные значения. Рабочая книга и рабочие листы хранят длины внутри в миллиметрах (MyWorkbook.Units).

Приложения Office обычно настраивают высоту строки автоматически в соответствии с шрифтом или вращением текста [внутри] содержимого ячейки. Этот случай идентифицируется с помощью RowHeightType, имеющего значение rhtAuto. Поскольку рабочий лист не может рассчитывать размер текста очень точно, автоматические высоты строк не записываются в FPSpreadsheet; они заменяются на default row height. Высота строки по умолчанию также используется, если строка пуста, т.е. не содержит никаких ячеек данных. Его значение можно изменить, вызвав WriteDefaultRowHeight() или используя свойство DefaultRowHeight. В WriteDefaultRowHeight единицы должны быть указаны в DefaultRowHeight, [где] они считаются линиями. Аналогично, default column width может быть задана с помощью WriteDefaultColWidth() или свойством DefaultColWidth (в символах).

Для того, чтобы перехватить [установку] высоты строк автоматически и по умолчанию, вызовите метод WriteRowHeight(). Эти записи строк идентифицируются с помощью RowHeightType, имеющего значение rhtCustom. Точно так же ширина столбцов может быть установлена на определенное значение вызовом WriteColWidth(). ColWidthType этих столбцов cwtCustom.

Высоту/ширину конкретной строки/столбца можно получить с помощью методов GetRowHeight или GetColHeight. Обратите внимание, что эти методы возвращают ширину строк/столбцов по умолчанию, если нет записей TRow/TCol.

pascal
type TsWorksheet = class
      ...
      { Установка высоты строки }
      procedure WriteRowHeight(ARowIndex: Cardinal; AHeight: Single; AUnits: TsSizeUnits);
      { Установка ширины столбца }
      procedure WriteColWidth(AColIndex: Cardinal; AWidth: Single; AUnits: TsSizeUnits);
      { Установка высоты строки по умолчанию }
      procedure WriteDefaultRowHeight(AHeight: Single; AUnits: TsSizeUnits);
      {Установка ширины столбца по умолчанию }
      procedure WriteDefaultColWidth(AWidth: Single; AUnits: TsSizeUnits);
    
      { Возврат высоты строки }
      function GetRowHeight(ARowIndex: Cardinal; AUnits: TsSizeUnits): Single;
      { Возврат ширины столбца }
      function GetColWidth(AColIndex: Cardinal; AUnits: TsSizeUnits): Single;
      { Возврат высоты строки по умолчанию }
      function ReadDefaultRowHeight(AUnits: TsSizeUnits): Single;
      { Возврат ширины столбца по умолчанию }
      function ReadDefaultColWidth(AUnits: TsSizeUnits): Single;
    
      property DefaultRowHeight: Single;  // в линиях
      property DefaultColWidht: Single;   // в символах

Существуют также перегруженные версии этих методов, для которых не требуется параметр AUnits. В этом случае высота строк определяются в терминах количества строк, а ширина столбцов определяется в терминах количества символов. Обратите внимание, что эти варианты из предыдущих версий и теперь устарели.

Элемент FormatIndex формата строк и столбцов применяется ко всей строке или столбцу. Как и в ячейках, эти форматы хранятся в виде записей TsCellFormat во внутреннем списке книг. Row and column formats в основном применяются к пустым ячейкам, но если добавлена новая ячейка, она автоматически получит формат строки или столбца. (Если обе строки и столбец имеют разные форматы, тогда будет использоваться формат строки).

Формулы

Два вида формул поддерживаются FPSpreadsheet:

FPSpreadsheet может [производить] преобразования между формулами строк и RPN. Формулы в обоих типах могут быть рассчитаны.

В более старых версиях FPSpreadsheet формулы сохранялись непосредственно в записи ячейки. Это было сделано, чтобы получить анализируемые формулы для более быстрого вычисления. Формулы хранятся в дереве Formulas рабочего листа. Запись формулы содержит индекс строки и столбца ячейки, к которой относится формула, строковое представление формулы, а также дерево парсера для быстрой оценки.

FPSpreadsheet поддерживает большинство формул, предоставляемых обычными приложениями электронных таблиц. Однако при чтении файла, созданного этими приложениями, всегда существует вероятность того, что [в нем] содержится не поддерживаемая формула. Чтобы избежать сбоев fpspreadsheet, чтение формул по умолчанию отключено; ячейка отображает только результат формулы, написанной приложением Office. Чтобы активировать чтение формул, перед открытием файла добавьте элемент boReadformulas в [свойстве] Options книги. Если в этом случае возникает ошибка, читатель [(парсер)] обычно обходит исключение, записывает сообщение об исключении в журнал ошибок книги и продолжает чтение. Если вы хотите, чтобы чтение останавливалось, вы должны добавить boAbortReadingOnFormulaError в Options книги.

Формулы могут ссылаться на данные в других листах той же книги ("3d формулы"), применяя синтаксис Excel (см. ниже). Внешние ссылки на электронные таблицы в других файлах не поддерживаются.

Вычисление формул обычно не требуется, когда файл написан [при помощи] FPSpreadsheet для открытия в приложении Office, потому что он автоматически вычисляет результаты формулы. Однако, если один и тот же файл открывается в приложении, основанном на FPSpreadsheet, вычисленные ячейки будут пустыми, потому что формулы по умолчанию автоматически не вычисляются. Чтобы активировать вычисление формул перед написанием электронной таблицы в файл, вы должны добавить опцию boCalcBeforeSaving в [свойство] Options книги.

Если FPSpreadshet используется в интерактивном приложении (таком, как демка «spready», расположенной в папке examples в [корневом каталоге] установки FPSpreadsheet), желательно автоматически вычислять формулы, когда пользовательские строки или значения ячеек изменяются пользователем. Этого можно достичь с помощью опции boAutoCalc в [свойстве] Options книги.

Таким образом, наиболее общая установка в отношении формул [такова]

pascal
MyWorkbook.Options := MyWorkbook.Options + [boReadFormulas, boCalcBeforeSaving, boAutoCalc];

Вычисление формул можно запускать вручную, вызывая метод CalcFormulas рабочего листа или рабочей книги. Последнее абсолютно необходимо, когда книга содержит 3d формулы, где результат одной ячейки может влиять на ячейки в других листах. Если есть формулы [, используемые] только внутри рабочего листа, то достаточно [использование свойства] CalcFormulas рабочего листа.

Строковые формулы

Строковые формулы записываются так же, как и в приложениях Office. Метод рабочей таблицы для создания строковой формулы WriteFormula:

pascal
var
      MyWorksheet: TsWorksheet;
    //...
      MyWorksheet.WriteFormula(0, 1, '=ROUND(A1+B2+1.215,0)');
      // По умолчанию используйте десятичную точку и запятую как разделитель списков!

Несколько замечаний по syntax :

pascal
var
      MyWorksheet: TsWorksheet;
    //...
      MyWorksheet.WriteFormula(0, 1, '=ROUND(A1+B2+1,215;0)', true);
      // Из-за "true" парсер формулы воспринимает запятую как десятичный разделитель и
      // точку с запятой в качестве разделителя списков, если формат FormatSettings книги yстановлен как здесь.

Use the worksheet methods ReadFormula or ReadFormulaAsString to retrieve the string formula assigned to the cell. The pointer to the cell must be given as a parameter. The latter function accepts an additional (boolean) parameter ALocalized to use the decimal and list separators of the workbook's FormatSettings for creation of the formula string.

Используйте методы ReadFormula или ReadFormulaAsString рабочего листа для получения строковой формулы, присвоенной ячейке. Указатель на ячейку должен быть определен как параметр. Последняя функция принимает дополнительный (логический) параметр ALocalized для использования десятичных [разделителей] и разделителей списков свойства FormatSettings рабочей книги для создания строки формулы.

pascal
var
      MyWorksheet: TsWorksheet;
      cell: PCell;
    //...
      cell := MyWorksheet.FindCell(0, 1);
      WriteLn('Формула во внутреннем формате - ', MyworkSheet.ReadFormula(cell));
      WriteLn('Локализованная формула - ', MyWorksheet.ReadFormulaAsString(cell, true));
    //-------------------------------------------------------------------
    // Предыдущий пример приведет к следующему результату
    ?????????????? ???? ???????????????????? ?????????????? - ROUND(A1+B2+1.215,0)
    ???????????????????????????? ?????????????? - ROUND(A1+B2+1,215;0)

Формулы RPN (Обратной польской нотации)

На уровне приложения в основном используются строковые формулы, а формулы RPN имеют мало практического значения. Поэтому документация формул RPN была удалена из этой основной вики FPSpreadsheet и может быть найдена в статье "Формулы RPN в FPSpreadsheet".

Общие формулы и формулы массива

Список встроенных формул

FPSpreadsheet поддерживает более 80 встроенных формул. Чтобы не взорвать эту страницу вики, большая часть документации по этим формулам была перенесена в отдельный документ "Список формул".

Чтобы узнать больше о доступных функциях, посмотрите файл testcases_calcrpnformula.inc в папке tests [в корневом каталоге] установки FPSpreadsheet, где каждая функция включена с хотя бы одним примером.

Расширение FPSpreadsheet по пользовательским формулам

Хотя встроенные формулы охватывают большинство приложений, может потребоваться доступ к формуле, доступной в приложении Office, но не в таблице FPSpreadsheet. По этой причине библиотека поддерживает механизм регистрации, который позволяет добавлять пользовательские функции к электронным таблицам. Это можно сделать, вызвав процедуру RegisterFunction из модуля fpsExprParser :

pascal
procedure RegisterFunction(const AName: ShortString; const AResultType: Char;
      const AParamTypes: String; const AExcelCode: Integer; ACallBack: TsExprFunctionCallBack); overload;
    
    procedure RegisterFunction(const AName: ShortString; const AResultType: Char;
      const AParamTypes: String; const AExcelCode: Integer; ACallBack: TsExprEventCallBack); overload;
pascal
type
      TsExprFunctionCallBack = procedure (var Result: TsExpressionResult; const Args: TsExprParameterArray);
      TsExprFunctionEvent = procedure (var Result: TsExpressionResult; const Args: TsExprParameterArray) of object;

TsExpressionResult - это вариантная запись, содержащая данные результата или аргумента нескольких типов:

pascal
type
      TsResultType = (rtEmpty, rtBoolean, rtInteger, rtFloat, rtDateTime, rtString,
        rtCell, rtCellRange, rtError, rtAny);
    
      TsExpressionResult = record
        Worksheet       : TsWorksheet;
        ResString       : String;
        case ResultType : TsResultType of
          rtEmpty       : ();
          rtError       : (ResError       : TsErrorValue);
          rtBoolean     : (ResBoolean     : Boolean);
          rtInteger     : (ResInteger     : Int64);
          rtFloat       : (ResFloat       : TsExprFloat);
          rtDateTime    : (ResDateTime    : TDatetime);
          rtCell        : (ResRow, ResCol : Cardinal);
          rtCellRange   : (ResCellRange   : TsCellRange);
          rtString      : ();
      end;
    
      TsExprParameterArray = array of TsExpressionResult;

В качестве примера мы приводим здесь код для формулы CONCATENATE(), которая объединяет две или более строки:

pascal
const
      INT_EXCEL_SHEET_FUNC_CONCATENATE = 336;  
    ...
      RegisterFunction('CONCATENATE', 'S', 'S+', INT_EXCEL_SHEET_FUNC_CONCATENATE, @fpsCONCATENATE);
    
    procedure fpsCONCATENATE(var Result: TsExpressionResult; const Args: TsExprParameterArray);
    // CONCATENATE( text1, text2, ... text_n )
    var
      s: String;
      i: Integer;
    begin
      s := '';
      for i:=0 to Length(Args)-1 do
      begin
        if Args[i].ResultType = rtError then
        begin
          Result := ErrorResult(Args[i].ResError);
          exit;
        end;
        s := s + ArgToString(Args[i]);
        // "ArgToString" упрощает получение строки из TsExpressionResult, 
        // поскольку строка может содержаться в ResString и в полях ResCell.
        // Такая функция существует для каждого базового типа данных.
      end;
      Result := StringResult(s);
      //"StringResult" хранит строку s в поле ResString объекта 
      // TsExpressionResult и устанавливает для ResultType значение rtString.
      // Такая функция существует для каждого базового типа данных.
    end;

В папке examples/other в [корневом каталоге] установки FPSpreadsheet имеется разработанный пример (demo_formula_func.pas). В этой демке добавлены четыре финансовые функции (FV(), PV(), PMT(), RATE()) в FPSpreadsheet.

Неподдерживаемые формулы

Иногда требуется создавать файлы для приложений Office с формулами, не поддерживаемыми [компонентом] FPSpreadsheet. Это возможно в некоторой степени, когда опция boIgnoreFormulas рабочей книги активна. Тогда любая произвольная формула может быть записана в ячейку, а формула не проверяется и не оценивается. [Рабочая] книга может быть записана в файл .ods или .xlsx. Старый формат файла xls не может быть использован, потому что формулу необходимо проанализировать для создания необходимой формулы RPN.

В папке examples/other вы можете найти образец проекта demo_ignore_formula , который создает файл ods со ссылками на другой файл данных. Внешние ссылки обычно не поддерживаются FPSpreadsheet, поэтому должны быть использованы обходные методы [их] игнорирования. Обратите внимание, что этот пример не работает с xlsx, потому что Excel записывает информацию о внешних ссылках для разделения XML-файлов в контейнере xlsx.

Форматирование ячеек

Форматы числа и даты/времени

Значения чисел и даты/времени могут отображаться в различных форматах. В FPSpreadsheet это может быть достигнуто двумя способами:

Форматы чисел могут быть указаны с помощью этих методов [рабочего] листа:

pascal
type
      TsWorksheet = class
      public
        // Установка только числовых форматов
        function WriteNumberFormat(ARow, ACol: Cardinal; ANumberFormat: TsNumberFormat;
          const AFormatString: String = ''): PCell; overload;
        procedure WriteNumberFormat(ACell: PCell; ANumberFormat: TsNumberFormat;
          const AFormatString: String = ''); overload;  
    
        function WriteNumberFormat(ARow, ACol: Cardinal; ANumFormat: TsNumberFormat;
          ADecimals: Integer; ACurrencySymbol: String = ''; APosCurrFormat: Integer = -1;
          ANegCurrFormat: Integer = -1): PCell; overload;
        procedure WriteNumberFormat(ACell: PCell; ANumFormat: TsNumberFormat;
          ADecimals: Integer; ACurrencySymbol: String = '';
          APosCurrFormat: Integer = -1; ANegCurrFormat: Integer = -1); overload;
    
        function WriteFractionFormat(ARow, ACol: Cardinal; AMixedFraction: Boolean;
          ANumeratorDigits, ADenominatorDigits: Integer): PCell; overload;
        procedure WriteFractionFormat(ACell: PCell; AMixedFraction: Boolean;
          ANumeratorDigits, ADenominatorDigits: Integer); overload;
    
        // Установка только формата дата/время  
        function WriteDateTimeFormat(ARow, ACol: Cardinal; ANumberFormat: TsNumberFormat;
          const AFormatString: String = ''): PCell; overload;
        procedure WriteDateTimeFormat(ACell: PCell; ANumberFormat: TsNumberFormat;
          const AFormatString: String = ''); overload;
    
    
        // Установка значений ячеек и числовых форматов за один вызов
    
        // числовые значения
        function WriteNumber(ARow, ACol: Cardinal; ANumber: double;
          AFormat: TsNumberFormat = nfGeneral; ADecimals: Byte = 2;
          ACurrencySymbol: String = ''): PCell; overload;
        procedure WriteNumber(ACell: PCell; ANumber: Double; AFormat: TsNumberFormat = nfGeneral;
          ADecimals: Byte = 2; ACurrencySymbol: String = ''); overload;
        function WriteNumber(ARow, ACol: Cardinal; ANumber: double;
          AFormat: TsNumberFormat; AFormatString: String): PCell; overload;
        procedure WriteNumber(ACell: PCell; ANumber: Double;
          AFormat: TsNumberFormat; AFormatString: String); overload;   
    
        // значения дата/время
        function WriteDateTime(ARow, ACol: Cardinal; AValue: TDateTime;
          AFormat: TsNumberFormat = nfShortDateTime; AFormatStr: String = ''): PCell; overload;
        procedure WriteDateTime(ACell: PCell; AValue: TDateTime;
          AFormat: TsNumberFormat = nfShortDateTime; AFormatStr: String = ''); overload;
        function WriteDateTime(ARow, ACol: Cardinal; AValue: TDateTime;
          AFormatStr: String): PCell; overload;
        procedure WriteDateTime(ACell: PCell; AValue: TDateTime;
          AFormatStr: String); overload;  
    
        // значения денежной валюты
        function WriteCurrency(ARow, ACol: Cardinal; AValue: Double;
          AFormat: TsNumberFormat = nfCurrency; ADecimals: Integer = 2;
          ACurrencySymbol: String = '?'; APosCurrFormat: Integer = -1;
          ANegCurrFormat: Integer = -1): PCell; overload;
        procedure WriteCurrency(ACell: PCell; AValue: Double;
          AFormat: TsNumberFormat = nfCurrency; ADecimals: Integer = -1;
          ACurrencySymbol: String = '?'; APosCurrFormat: Integer = -1;
          ANegCurrFormat: Integer = -1); overload;
        function WriteCurrency(ARow, ACol: Cardinal; AValue: Double;
          AFormat: TsNumberFormat; AFormatString: String): PCell; overload;
        procedure WriteCurrency(ACell: PCell; AValue: Double;
          AFormat: TsNumberFormat; AFormatString: String); overload;     
      ...
Встроенные форматы чисел

Встроенные форматы определяются перечислением TsNumberFormat. Несмотря на свое название, элементы охватывают как числа, так и дату/время:

pascal
type
      TsNumberFormat = (
        // универсальный для всех номеров
        nfGeneral,
        // числа
        nfFixed, nfFixedTh, nfExp, nfPercentage, nfFraction,
        // денежная валюта
        nfCurrency, nfCurrencyRed, 
        // дата и время
        nfShortDateTime, nfShortDate, nfLongDate, nfShortTime, nfLongTime,
        nfShortTimeAM, nfLongTimeAM, nfDayMonth, nfMonthYear, nfTimeInterval,
        // другие (использующие строку формата)
        nfCustom);

Как уже отмечалось, в рабочей книге есть свойство FormatSettings, которое предоставляет дополнительную информацию для управления окончательным форматированием. Это, по существу, копия DefaultFormatSettings, объявленная в модуле sysutils (элементы LongDateFormat и ShortDateFormat слегка изменены для лучшего соответствия настройки по умолчанию в основных приложениях электронных таблиц). Основная цель FormatSettings - добавить простой способ локализации в числовые форматы.

Строки формата чисел

В дополнение к этим заранее определенным форматам более специализированное форматирование может быть достигнуто с использованием константы формата nfCustom вместе со специальной строкой формата. Строка формата построена в соответствии с синтаксисом Excel, который близок к синтаксису команд FormatFloat и FormatDateTime команды fpc (см. интерактивную справку для этих функций).

Вот основной список используемых символов:

Символ Определение Строка формата: число --> Выходная строка
General Отображает все десятичные знаки числа 'General': · 1.2345678 --> '1.2345678'
0 Отображает не значащие нули, если число имеет меньше знаков, чем [количество] нулей в формате. Если [строка формата] используется для десятичных знаков, то число округляется до такого количества знаков после запятой, что и 0. '000': 1 --> '001' · '0.0': 1 --> '1.0' · '0.0': 1.2345678 --> '1.2'
* Как [и для] "0" выше, но не отображает не значащие нули. '0.*': 1 --> '1.' · '0.*': 1.2345678 --> '1.2'
? Как [и для] "0" выше, но не существенные нули заменяются пробелами. Хорошо для выравнивания десятичных точек и фракций '??0': 1 --> ' 1' · '0.0??': 1 --> '1.0 '
. Десятичный разделитель; будет заменено значением, используемым в DecimalSeparator [параметра] FormatSettings рабочей книги '0.00': 8.9 --> '8.90'
, Разделитель тысячных [разрядов]; будет заменено значением, используемым в ThousandSeparator [параметра] FormatSettings рабочей книги. Если [сепаратор указан] в конце последовательности форматирования числа, [то] отображаемое значение делится на 1000. '#,##0.00': 1200 --> '1,200.00' · '0.00,': 1200 --> '1.20'
E+, e+ Отображает число в экспоненциальном формате. Цифры, используемые для показателя, определяются числом нулей, добавленным этим символом. Знак экспонента показан для положительных и отрицательных показателей. '0.00E+00': 1200 --> 1.20E+03
E-, e- Отображает число в экспоненциальном формате. Цифры, используемые для показателя, определяются числом нулей, добавленным этим символом. Знак экспонента показан только для отрицательных показателей. '0.00e-000': 1200 --> 1.20e003
% Отображает число как «процент», т.е. число умножается на 100 и добавляется знак %. '0.0%': 0.75 --> 75.0%
/ Этот символ имеет два значения: если ячейка представляет собой "число", то косая черта означает форматирование как дробь, числитель и знаменатель должны следовать зарезервированному месту. Если ячейка представляет "дату/время", то косая черта обозначает разделитель даты, который будет заменен на DateSeparator в [параметре] FormatSettings рабочего листа '#/#': 1.5 --> '3/2' · '# #/#': 1.5 --> '1 1/2' · '# #/16': 1.5 --> '1 8/16' · также: см. примеры даты/времени ниже
: Разделитель между часами, минутами и секундами значения даты/времени. Будет заменен [на] TimeSeparator [параметра] FormatSettings рабочей книги. смотри пример ниже
yyyy Зарезервированное место для года значения даты/времени. Год отображается как четырехзначное число. 'yyyy/mm/dd': · Jan 3, 2012 --> '2012-01-03' · В этом примере DateSeparator является символом тире (-).
yy Зарезервированное место для года значения даты/времени. Год отображается как двузначное число. 'yy/mm/dd': · Jan 3, 2012 --> '12-01-03'
m Зарезервированное место для месяца значения даты/времени. Месяц отображается как число без дополнительных цифр. · Обратите внимание, что код m также можно интерпретировать как «минуты» значения времени (см. ниже). 'yyyy/m/dd': · Jan 3, 2012 --> '2012-1-03'
mm Зарезервированное место для месяца значения даты/времени. Месяц отображается как двузначное число, то есть начальный ноль добавляется с января по сентябрь. · Обратите внимание, что код mm также может быть интерпретирован как "минуты" (см. ниже). 'yyyy/mm/dd': · Jan 3, 2012 --> '2012-01-03'
mmm Зарезервированное место для месяца значения даты/времени. Месяц отображается [в виде] аббревиатуры. 'yyyy/mmm/dd': · Jan 3, 2012 --> '2012-Jan-03'
mmmm Зарезервированное место для месяца значения даты/времени. Месяц отображается полным именем. 'yyyy/mmm/dd': · Jan 3, 2012 --> '2012-January-03'
d Зарезервированное место дня значения даты/времени, которое будет отображаться в виде числа. День отображается как простое число без добавления начального нуля. 'yyyy/mm/d': · Jan 3, 2012 --> '2012-01-3'
dd Зарезервированное место дня значения даты/времени, которое будет отображаться в виде числа. dd добавляет [лидирующий] ноль в однозначные числа. 'yyyy/mm/dd': · Jan 3, 2012 --> '2012-01-03'
ddd Зарезервированное место дня значения даты/времени. День отображается в виде аббревиатуры. 'dddd, yyyy/mm/ddd': · Jan 03, 2012 --> 'Tue 2012-01-03'
dddd Зарезервированное место дня значения даты/времени. День отображается полным именем. 'dddd, yyyy/mmmm/dd': · Jan 03, 2012 --> 'Tuesday 2012-01-03'
h Зарезервированное место часовой части значения даты/времени. Час отображается как простое число без добавления начального нуля. 'h:mm': · 0.25 --> '6:00'
hh Зарезервированное место часовой части значения даты/времени. Час отображается с начальным нулем, если час меньше 10. 'hh:mm': · 0.25 --> '06:00'
[hh], или [h] Отображает прошедшее время, так что часовая часть может стать больше 23 '[h]:mm': · 1.25 --> '30:00'
m Зарезервированное место минутной части значения даты/времени. Минуты показаны как простое число без добавления начального нуля. Заметим, что если коды m окружены символами даты (y, d), то они интерпретируются как "месяц". 'h:m': · 0.25 --> '6:0'
mm Зарезервированное место минутной части значения даты/времени. Минуты с одной цифрой отображаются с начальным нулем. Заметим, что если код mm окружен символами даты (y, d), то он интерпретируется как "месяц". 'h:mm': · 0.25 --> '6:00'
[mm], или [m] Отображает прошедшее время так, что минутная часть может стать больше 59 '[mm]:ss': · 1.25 --> '1800:00'
s Зарезервированное место секундной части значения даты/времени. Секунды отображаются как простое число без добавления начального нуля. 'hh:mm:s': · 0.25 --> '06:00:0'
ss Зарезервированное место секундной части значения даты/времени. Секунды с одной цифрой отображаются с начальным нулем. 'hh:mm:ss': · 0.25 --> '06:00:00'
[ss], или [s] Отображает прошедшее время так, что секундная часть может стать больше, чем 59 '[ss]': · 1.25 --> '108000'
AM/PM, am/pm, A/P, или a/p Отображает время в 12-часовом формате. 'hh:mm:ss AM/PM': · 0.25 --> '6:00:00 AM'
" Текст, заключенный в кавычки, вставляется в форматированные строки буквально. 'yyyy"/"mm"/"dd': · Jan 3, 2012 --> '2012/01/03' (т. е. / не заменяется свойством DateSeparator рабочей книги).
\ Следующий символ строки формата отображается в строке результата буквально. Сам \ не отображается. 'yyyy\/mm\/dd': · Jan 3, 2012 --> '2012/01/03'
; Строка формата может содержать до трех разделов, разделенных точкой с запятой. Первый раздел используется для положительных чисел, второй - для отрицательных чисел, а третий - для нулевых чисел. Если третий раздел отсутствует, то нулевое значение форматируется, как указано в первом разделе. Если второй раздел также отсутствует, то все значения форматируются в соответствии с первым разделом. '"#,##0"$"';-#,##0"$";"-"': · 1200 --> '1,200$' · -1200 --> '1,200$' · 0 --> '-'
(, и ) Иногда используется для значений валюты, указывающих отрицательные числа, вместо знака "минус" '#,##0"$";(#,##0)"$"': · -1200 --> '(1200)$'
[red] Отформатированная строка отображается в указанном цвете. Вместо [red] вы можете использовать соответственно [black], [white], [green], [blue], [magenta], [yellow], или [cyan]. Часто используется для выделения отрицательных значений валюты. '"$" #,##0.00;[red]("$" #,##0.00)': · -1200 --> '($ 1200.00)'

Цвета

FPSpreadsheet поддерживает цвета для текста, фона ячейки и границ ячеек. Основные цвета EGA объявлены в модуле fpstypes как константы:

Predefined colors

pascal
type
      TsColor = DWORD;
    
    const
      scBlack       = $00000000;
      scWhite       = $00FFFFFF;
      scRed         = $000000FF;
      scGreen       = $0000FF00;
      scBlue        = $00FF0000;
      scYellow      = $0000FFFF;
      scMagenta     = $00FF00FF;
      scCyan        = $00FFFF00;
      scDarkRed     = $00000080;
      scDarkGreen   = $00008000;
      scDarkBlue    = $00800000;
      scOlive       = $00008080;
      scPurple      = $00800080;
      scTeal        = $00808000;
      scSilver      = $00C0C0C0;
      scGray        = $00808080;
      scGrey        = scGray; // переопределить, чтобы разрешить различное правописание
    
      // Идентификатор неопределенного цвета 
      scNotDefined  = $40000000;
    
      // Идентификатор прозрачного цвета 
      scTransparent = $20000000;

[Свойство] TsColor представляет значение rgb [значение] цвета, а для красных, зеленых и синих компонентов используется один байт. Результирующее число представлено обратным порядком байт (Little Endian Notation), т. е. сначала в памяти появляется значение красного [цвета]: $00BBGGRR. (Это напрямую совместимо с значениями цвета, как [оно] определено в модуле graphics.)

Старший байт обычно равен нулю, но используется внутри для определения специальных значений цвета, например, для неопределенных или прозрачных цветов.

Note-icon.png

Примечание: В более старых версиях цвета библиотеки были определены как индексы в цветовой палитре. ЭТО НЕ БОЛЬШЕ РАБОТАЕТ.

Модуль fpsutils содержит некоторые полезные функции для модификации цветов :

возвращает имя цветов, определенных выше, или строку, показывающую компоненты rgb для других цветов.

возвращает scBlack для «яркого», scWhite для "темного" входного цвета.

осветляет или затемняет цвет, применяя коэффициент tint = -1 .. + 1, где -1 означает "100% затемнение", +1 означает "100% осветление", а 0 означает "без изменений". Цветовой оттенок сохраняется.

Фон ячейки

Фон ячейки может быть заполнен предопределенными шаблонами, которые идентифицируются записью TsFillPattern::

pascal
type
      TsFillPattern = record
        Style: TsFillStyle;   // заполняет шаблон стиля, как определено ниже
        FgColor: TsColor;     // цвет переднего плана заливки шаблона
        BgColor: TsColor;     // цвет фона заливки шаблона
      end;
    
      TsFillStyle = (fsNoFill, fsSolidFill, fsGray75, fsGray50, fsGray25, fsGray12, fsGray6,
        fsStripeHor, fsStripeVert, fsStripeDiagUp, fsStripeDiagDown,
        fsThinStripeHor, fsThinStripeVert, fsThinStripeDiagUp, fsThinStripeDiagDown,
        fsHatchDiag, fsThinHatchDiag, fsThickHatchDiag, fsThinHatchHor);
pascal
type
      TsWorksheet = class
      public
        function WriteBackground(ARow, ACol: Cardinal; AStyle: TsFillStyle; APatternColor, ABackgroundColor: TsColor): PCell; overload;
        procedure WriteBackground(ACell: PCell; AStyle: TsFillStyle; APatternColor, ABackgroundColor: TsColor); overload;
    
        function WriteBackgroundColor(ARow, ACol: Cardinal; AColor: TsColor): PCell; overload;
        procedure WriteBackgroundColor(ACell: PCell; AColor: TsColor); overload;
    
        function ReadBackground(ACell: PCell): TsFillPattern;
        function ReadBackgroundColor(ACell: PCell): TsColor; overload;
        // ...
      end;
    
    var
      cell: PCell;
    ...
      // Пример 1: Присваивает шаблон тонких, горизонтальных, желтых полос на синем фоне, пустой ячейке A1 (строка 0, столбец 0)
      MyWorksheet.WriteBackground(0, 0, fsThinStripeHor, scYellow, scBlue);
    
      // Пример 2: Равномерный серый цвет фона ячейки B1 (строка 0, столбец 1), содержащий номер 3.14
      cell := MyWorksheet.WriteNumber(0, 1, 3.14);
      MyWorksheet.WriteBackgroundColor(cell, clSilver);

Границы ячеек

Ячейки можно обвести, рисуя границы вдоль их краев или диагональных линий. Существует четыре границы плюс две диагонали, перечисленные в типе данных TsCellBorder:

pascal
type
      TsCellBorder = (cbNorth, cbWest, cbEast, cbSouth, dbDiagUp, dbDiagDown);
      TsCellBorders = set of TsCellBorder;

Чтобы показать линию края, добавьте соответствующую границу к ячейке Borders (тип TsCellBorders, см. выше). Таким образом, каждый край ячейки может обрабатываться отдельно. Для этого используйте метод рабочего листа WriteBorders. Этот пример добавляет верхнюю и нижнюю границы к краям A1 и B1:

pascal
MyWorksheet.WriteBorders(0, 0, [cbNorth, cbSouth]);  // A1: строка 0, столбец 0
      MyWorksheet.WriteBorders(0, 1, [cbNorth, cbSourth]); // B1: строка 0, столбец 1

Линии обычно рисуются как тонкие, сплошные черные линии. Но можно изменить стиль линии и цвет каждой строки. Для этой цели ячейка предоставляет массив записей TsCellBorderStyle:

pascal
type
      TsLineStyle = (lsThin, lsMedium, lsDashed, lsDotted, lsThick, lsDouble, lsHair,
        lsMediumDash, lsDashDot, lsMediumDashDot, lsDashDotDot, lsMediumDashDotDot, lsSlantDashDot); 
    
      TsCellBorderStyle = record
        LineStyle: TsLineStyle;   
        Color: TsColor;
      end;
    
      TsCellBorderStyles = array[TsCellBorder] of TsCellBorderStyle;   
    
      TsWorksheet = class
      public
        function WriteBorderStyle(ARow, ACol: Cardinal; ABorder: TsCellBorder; AStyle: TsCellBorderStyle): PCell; overload;
        procedure WriteBorderStyle(ACell: PCell; ABorder: TsCellBorder; AStyle: TsCellBorderStyle); overload;
    
        function WriteBorderStyle(ARow, ACol: Cardinal; ABorder: TsCellBorder; ALineStyle: TsLineStyle; AColor: TsColor): PCell; overload;
        procedure WriteBorderStyle(ACell: PCell; ABorder: TsCellBorder; ALineStyle: TsLineStyle; AColor: TsColor); overload;
    
        function WriteBorderColor(ARow, ACol: Cardinal; ABorder: TsCellBorder; AColor: TsColor): PCell; overload;
        proceure WriteBorderColor(ACell: PCell; ABorder: TsCellBorder; AColor: TsColor): PCell; overload;
    
        function WriteBorderLineStyle(ARow, ACol: Cardinal; ABorder: TsCellBorder; ALineStyle: TsLineStyle): PCell; overload;
        procedure WriteBorderLineStyle(ACell: PCell; ABorder: TsCellBorder; ALineStyle: TsLineStyle): PCell; overload;
    
        function WriteBorderStyles(ARow, ACol: Cardinal; const AStyles: TsCellBorderStyles): PCell; overload;      
        procedure WriteBorderStyles(ACell: PCell; const AStyles: TsCellBorderStyles); overload;
    
        function WriteBorders(ARow, ACol: Cardinal; ABorders: TsCellBorders): PCell; overload
        procedure WriteBorders(ACell: PCell; ABorders: TsCellBorders); overload
    
        function ReadCellBorders(ACell: PCell): TsCellBorders;
        function ReadCellBorderStyle(ACell: PCell; ABorder: TsCellBorder): TsCellBorderStyle;
        function ReadCellBorderStyles(ACell: PCell): TsCellBorderStyles;
        ...
      end;

Стиль границы данной ячейки может быть задан следующими способами, представленными в рабочем листе:

Этот пример добавляет тонкую черную границу к вершине [ячейки] и толстую синюю границу по нижней [кромке] ячеек A1 и B1:

pascal
var
      cellA1, cellB1: PCell;
    ...
      cellA1 := MyWorksheet.WriteBorders(0, 0, [cbNorth, cbSouth]);    // ячейка A1: строка 0, столбец 0
      MyWorksheet.WriteBorderStyle(cellA1, cbNorth, lsThin, scBlack);  
      MyWorksheet.WriteBorderStyle(cellA1, cbSouth, lsThick, scBlue);
    
      cellB1 := MyWorksheet.WriteBorders(0, 1, [cbNorth, cbSouth]);    // ячейка B1: строка 0, столбец 1
      MyWorksheet.WriteBorderStyles(cellB1, cellA1^.BorderStyles);     // копируем все стили границ из ячейки A1 в B1

Note-icon.png

Примечание: Диагональные линии не поддерживаются [форматами] sfExcel2 и sfExcel5 - они просто опускаются. sfExcel8 и sfOOXML используют один и тот же стиль линии, и цвет для обеих диагоналей; стиль границы, [определенный для] диагональной [снизу - вверх] линии, считается действительным также для диагональной линии [сверху - ] вниз. Некоторые [парсеры] не поддерживают все стили линий, перечисленных в TsLineStyle. В этом случае используются соответствующие стили замены линий.

Шрифты

Текст ячейки может отображаться в разных шрифтах. С этой целью в книге содержится список элементов TsFont:

pascal
type
      TsFont = class
        FontName: String;
        Size: Single;   
        Style: TsFontStyles;
        Color: TsColor;
        Position: TsFontPosition;
      end;

Каждая ячейка снабжается индексом в списке шрифтов.

Чтобы назначить конкретный шрифт ячейке, используйте один из следующих методов TsSpreadsheet:

pascal
type
      TsSpreadsheet = class
      public
        function  WriteFont(ARow, ACol: Cardinal; const AFontName: String;
          AFontSize: Single; AFontStyle: TsFontStyles; AFontColor: TsColor): Integer; overload;
        procedure WriteFont(ARow, ACol: Cardinal; AFontIndex: Integer); overload;
        function WriteFontColor(ARow, ACol: Cardinal; AFontColor: TsColor): Integer;
        function WriteFontSize(ARow, ACol: Cardinal; ASize: Integer): Integer;
        function WriteFontStyle(ARow, ACol: Cardinal; AStyle: TsFontStyles): Integer; 
        // плюс: перегруженные версии, принимающие указатель на ячейку записи, а не индекс строки и столбца в качестве параметра
        // ...
      end;

Список шрифтов рабочей книги содержит по крайней мере один элемент, который является шрифтом по умолчанию для ячеек с немодифицированными шрифтами. По умолчанию это [шрифт] "Arial" [размером] 10pt. Используйте метод SetDefaultFont рабочей книги, чтобы назначить другой шрифт первому элементу списка.

Шрифт в указанном индексе списка шрифтов можно просмотреть, вызвав функцию рабочей книги GetFont. Количество доступных шрифтов возвращается [свойством] GetFontCount.

Вот пример , который уменьшает размер всех 10pt-овых шрифтов Arial до 9pt:

pascal
var
      i: Integer;
      font: TsFont;
    begin
      for i := 0 to MyWorkbook.GetFontCount-1 do
      begin
        font := MyWorkbook.GetFont(i);
        if (font.FontName = 'Arial') and (font.Size = 10.0) then
          font.Size := 9.0;
      end;
    end;

Форматирование Rich-text

В дополнение к использованию конкретного шрифта для каждой ячейки также можно указать конкретные атрибуты шрифта для отдельных символов или групп символов в каждом тексте ячейки. Следуя нотации Excel, мы называем эту функцию "форматированием Rich-text" (хотя это не имеет ничего общего с форматом файла *.rtf).

С этой целью модуль fpstypes объявляет тип TsRichTextParams, который представляет собой массив записей TsRichTextParam:

pascal
type
      TsRichTextParam = record
        FontIndex: Integer;
        FirstIndex: Integer;
      end;
    
      TsRichTextParams = array of TsRichTextParam;

FontIndex ссылается на индекс шрифта в FontList рабочей книги, который будет использоваться для форматирования символов, начинающихся с индекса FirstIndex. Нумерация индекса строковых символов FirstIndex начинается с 1.

Существует два способа добавления форматирования "rich-text" в ячейке:

pascal
MyWorksheet.WriteTextAsHTML(0, 0, 'Area (m<sup>2</sup>');
pascal
var
      richTextParams: TsRichTextParams;
      fnt: TsFont;
    begin
      SetLength(rtp, 2);
      fnt := MyWorksheet.ReadCellFont(0, 0);
      richTextParams[0].FirstIndex := 8; // Группа верхнего индекса начинается с «2», который является символом #8 текста ячейки.
      richTextParams[0].FontIndex := MyWorkbook.AddFont(fnt.FontName, fnt.Size, fnt.Style, fnt.Color, fpSuperscript);
      richTextParams[1].FirstIndex := 9; // Обычный шрифт снова начинается с символа # 9.
      richTextParams[1].FontIndex := MyWorksheet.ReadCellFontIndex(0, 0);
      MyWorksheet.WriteUTF8Text(0, 0, 'Area (m2)', richTextParams);
    end;

Используйте метод рабочего листа DeleteRichTextParams, чтобы удалить форматирование rich-text из ранее отформатированной ячейки.

Note-icon.png

Примечание: Если ячейка должна иметь шрифт, отличный от шрифта по умолчанию рабочего листа, то этот шрифт должен быть записан в ячейку перед записью форматированного текста rich-text. В противном случае шрифт в неотформатированных регионах не будет обновлен.

Вращение текста

Обычно текст отображается в ячейках по горизонтали. Тем не менее, можно также поворачивать его на 90 градусов по часовой стрелке или против часовой стрелки. Кроме того, существует возможность установки горизонтальных символов вертикально друг над другом.

Если вам нужна эта функция, используйте метод рабочего листа WriteTextRotation и укажите направление текста элементом [свойства] перечислимого типа TsTextRotation:

pascal
type
      TsTextRotation = (trHorizontal, rt90DegreeClockwiseRotation,
        rt90DegreeCounterClockwiseRotation, rtStacked);
    
      TsWorksheet = class
      public
        function WriteTextRotation(ARow, ACol: Cardinal; ARotation: TsTextRotation): PCell; overload;
        procedure WriteTextRotation(ACell: PCell; ARotation: TsTextRotation); overload;
    
        function ReadTextRotation(ACell: PCell): TsTextRotation;
        // ...
      end;
    
      // пример для повернутого против часовой стрелки текста в ячейке A1:
      WriteTextRotation(0, 0, rt90DegreeCounterClockwizeRotation);

Warning-icon.png

Предупреждение: Более мелкие степени вращения, которые могут поддерживаться некоторыми форматами файлов электронной таблицы, игнорируются.

Выравнивание текста

По умолчанию текст ячейки выровнен по левому и нижнему краям ячейки, за исключением чисел, выровненных по правому краю. Это поведение можно изменить, используя методы рабочего листа WriteHorAlignment и WriteVertAlignment:

pascal
type
      TsHorAlignment = (haDefault, haLeft, haCenter, haRight);
      TsVertAlignment = (vaDefault, vaTop, vaCenter, vaBottom);    
    
      TsWorkbook = class
      public
        function WriteHorAlignment(ARow, ACol: Cardinal; AValue: TsHorAlignment): PCell; overload;
        procedure WriteHorAlignment(ACell: PCell; AValue: TsHorAlignment); overload;
        function ReadHorAlignment(ACell: PCell): TsHorAlignment;
    
        function WriteVertAlignment(ARow, ACol: Cardinal; AValue: TsVertAlignment): PCell; overload; 
        procedure WriteVertAlignment(ACell: PCell; AValue: TsVertAlignment); overload;
        function ReadVertAlignment(ACell: PCell): TsVertAlignment;
        // ...
      end;
    
      // Пример: [так] центрируется текст в ячейке А1 как по горизонтали, так и по вертикали
      MyWorkbook.WriteHorAlignment(0, 0, haCenter);
      MyWorkbook.WriteVertAlignment(0, 0, vaCenter);

Перенос слов

Текст, длина которого превышает ширину ячейки, может быть перенесен на несколько строк вызовом метода WriteWordwrap электронной таблицы:

pascal
type
      TsWorksheet = class
      public
        function WriteWordwrap(ARow, ACol: Cardinal; AValue: Boolean): PCell; overload;
        procedure WriteWordwrap(ACell: PCell; AValue: Boolean); overload;
        function ReadWordwrap(ACell: PCell): Boolean;
        //...
      end;
    
      // Пример: активация переноса слов в ячейке А1
      MyWorksheet.WriteWordwrap(0, 0, true);

Объединенные ячейки

Подобно приложениям Office, FPSpreadsheet поддерживает также возможность слияния ячеек в одну большую ячейку, которая часто используется как общий заголовок выше аналогичных столбцов. Просто вызовите MergeCells и передайте параметр, чтобы указать диапазон ячеек, которые нужно объединить, либо строку диапазона Excel (например, A1:D5), либо первую и последнюю строку и столбец:

pascal
MyWorksheet.MergeCells('A1:D5');
      // или: MyWorksheet.MergeCells(0, 0, 4, 3);  // первая строка, первый столбец, последняя строка, последний столбец

Содержимое и формат, отображаемые для объединенного диапазона, берутся из верхнего левого угла диапазона ячейки A1 в приведенном выше примере. Эта ячейка вызывается [свойством] MergeBase в библиотеке. За исключением этой угловой ячейки, [там] не должно быть никаких других ячеек в диапазоне. Если [они там окажутся], их содержимое и формат будут скрыты.

Чтобы разбить объединенный диапазон на отдельные ячейки, используйте команду Unmerge и передайте любую ячейку, находящуюся в объединенном диапазоне:

pascal
MyWorksheet.UnmergeCells('B1');
      // или: MyWorksheet.UnmergeCells(0, 1);   // строка, столбец любой ячейки в пределах диапазона

Объединенные ячейки могут быть прочитаны/записаны во все форматы файлов, за исключением sfCSV, sfExcel2 и sfExcel5, которые не поддерживают эту функцию изначально.

Информация, с которой объединены ячейки, хранится во внутреннем списке. В отличие от предыдущих версий, больше невозможно получить доступ к MergeBase из ячейки напрямую. Используйте следующие функции для извлечения информации об объединенных ячейках:

pascal
var
      cell, base: PCell;
      r1,c1,r2,c2: Cardinal;
    ...
      cell := MyWorksheet.FindCell('B1');
      if MyWorksheet.IsMerged(cell) then
      begin
        WriteLn('Ячейка B1 объединена.');
    
        MyWorksheet.FindMergedRange(cell, r1, c1, r2, c2);
        WriteLn('Объединенный диапазон - ' + GetCellRangeString(r1, c1, r2, c2));
    
        base := MyWorksheet.FindMergeBase(cell);
        WriteLn('Основная ячейка для слияния - ' + GetCellString(base^.Row, base^.Col));
      end;

Защита ячейки

Это описано в отдельном разделе ниже.

Дополнительная информация

Комментарии к ячейке

Комментарии могут быть прикреплены к любой ячейке путем вызова

pascal
MyWorksheet.WriteComment(0, 0, 'Это комментарий для ячейки A1');

Они хранятся во внутреннем списке рабочего листа. Используйте соответствующие методы рабочего листа для доступа к комментариям:

Гиперссылки

Гиперссылки могут быть прикреплены к ячейкам, чтобы связать ячейки с другими документами или другими ячейками в одной книге. Общий синтаксис для создания гиперссылок

pascal
procedure TWorksheet.WriteHyperlink(ARow, ACol: Cardinal; ATarget: String; ATooltip: String = '');

Note-icon.png

Примечание: Гиперссылки могут быть добавлены в пустые ячейки или в ячейки с контентом. В последнем случае отображаемый контент не изменяется гиперссылкой; в первом случае ячейка преобразуется в метку ячейки, показывающую цель гиперссылки. Имейте в виду, что OpenOffice/LibreOffice принимает гиперссылки только с нетекстовыми ячейками.

Примеры:

pascal
// Открытие веб-сайта www.google.com
      MyWorksheet.WriteText(0, 0, 'Открыть google');
      MyWorksheet.WriteHyperlink(0, 0, 'http://www.google.com');
    
      // Открытие локального файла с абсолютным путем "C:\readme.txt" (предполагается, [что это] Windows)
      MyWorksheet.WriteHyperlink(1, 0, 'file:///c:\readme.txt');
    
      // Открытие почтового клиента для отправки почты
      MyWorksheet.WriteText('Отправить письмо');
      MyWorksheet.WriteHyperlink(3, 0, 'mailto:somebody@gmail.com?subject=Test');
    
      // Переход к определенной ячейке 
      MyWorksheet.WriteText(5, 0, 'Переход к ячейке A10 на листе2');
      MyWorksheet.WriteHyperlink(5, 0, '#Sheet2!A10');
    
      // Переход в ячейку A10 на текущем листе и отображение всплывающей подсказки
      MyWorksheet.WriteHyperlink(5, 0, '#A10', 'Переход к ячейке A10');

Note-icon.png

Примечание: FPSpreadsheet не «следит» за ссылками, он предоставляет только механизм для получения доступа к связанным данным. Однако [компонент] TsWorksheetGrid из пакета laz_fpspreadsheet_visual запускает событие OnClickHyperlink, если ячейку с внешней гиперссылкой щелкают за доли секунды. В соответствующем обработчике событий вы можете, например, загрузить целевую электронную таблицу или открыть веб-браузер для отображения связанного веб-сайта. Если ссылка является внутренней ссылкой на другую ячейку в одной книге, таблица переходит к связанной ячейке.

Изображения

FPSpreadsheet поддерживает встраивание изображений в рабочие листы. Используйте один из методов рабочего листа WriteImage(), чтобы добавить изображение на рабочий лист:

pascal
MyWorksheet.WriteImage(row, col, filename, offsetX, offsetY, scaleX, scaleY);
      MyWorksheet.WriteImage(row, col, stream, offsetX, offsetY, scaleX, scaleY);
      MyWorksheet.WriteImage(row, col, imageindex, offsetX, offsetY, scaleX, scaleY);

Верхний/левый угол изображения помещается в верхний/левый угол ячейки в указанной строке и столбце. Параметры плавающей запятой offsetX, offsetY, scaleX и scaleY являются необязательными: они определяют смещение точки привязки этого изображения от угла ячейки и коэффициент увеличения. Путь к файлу изображения указывается как параметр filename. В качестве альтернативы можно использовать перегруженные версии, которые принимают поток [данных] вместо имени файла или индекса изображения в списке EmbeddedObj рабочей книги - используйте MyWorkbook.FindEmbeddedObj(имя файла), чтобы получить этот индекс для ранее загруженного изображения файл.

Обратите внимание, что FPSpreadsheet должен знать тип изображения для успешного импорта картинок. В настоящее время поддерживаются типы png , jpg , tiff , bmp , gif , svg , wmf , emf и pcx (Excel2007 не может читать импортированные изображения svg and pcx). Другие форматы могут быть зарегистрированы путем записи функции, которая определяет размер изображения и плотность пикселей, а также путем регистрации нового формата с помощью процедуры RegisterImageType - см. модуль fpsImages для [получения] примеров:

pascal
type
      TsImageType = integer;
      TGetImageSizeFunc = function (AStream: TStream; out AWidth, AHeight: DWord; out dpiX, dpiY: Double): Boolean;
    
    function RegisterImageType(AMimeType, AExtension: String; AGetImageSize: TGetImageSizeFunc): TsImageType;

Из-за различий в расчете высоты строки и ширины столбцов между приложениями FPSpreadsheet и Office невозможно правильно позиционировать изображения. Если точное положение изображения важно, вы должны соблюдать следующие правила:

Сортировка

Ячейки на рабочем листе можно сортировать по множеству критериев, вызывая метод Sort рабочего листа. Этот метод принимает запись TsSortParams, и края прямоугольника ячейки сортируются как параметры; в перегруженной версии прямоугольник ячейки также может быть задан с помощью строки диапазона типа Excel (например, 'A1:G10'):

pascal
type
      TsWorksheet = class
        // ...
        procedure Sort(const ASortParams: TsSortParams;
          ARowFrom, AColFrom, ARowTo, AColTo: Cardinal); overload;
        procedure Sort(ASortParams: TsSortParams; ARange: String); overload;
        // ...
      end;

Критерии сортировки определяются записью типа TsSortParams:

pascal
type
      TsSortParams = record
        SortByCols: Boolean;
        Priority: TsSortPriority;  // spNumAlpha ("Сначала числа") или spAlphaNum ("Сначала текст")
        Keys: TsSortKeys;
      end;    
    
      TsSortKey = record
        ColRowIndex: Integer;
        Options: TsSortOptions;    // set of [spDescending, spCaseInsensitive]
      end;

InitSortParams - это удобная утилита для инициализации параметров сортировки:

pascal
function InitSortParams(ASortByCols: Boolean = true; ANumSortKeys: Integer = 1;
      ASortPriority: TsSortPriority = spNumAlpha): TsSortParams;

Следующий фрагмент кода показывает типичный вызов сортировки:

pascal
var
      sortParams: TsSortParams;
    begin
      sortParams := InitSortParams(true, 2);  // сортировка по столбцам, 2 сортировочных ключа
    
      // первичный ключ сортировки: столбец 3, восходящая [сортировка], нечувствительный к регистру
      sortParams.Keys[0].ColRowIndex := 3;
      sortParams.Keys[0].Options := [ssoCaseInsensitive];
    
      // вторичный ключ сортировки: столбец 1, нисходящая [сортировка]
      sortParams.Keys[1].ColRowIndex := 1;
      sortParams.Keys[1].Options := [ssoDescending];
    
      // Блок сортировки распространяется между ячейкой A1 (строка=0, столбец=0) и F10 (строка=9, столбец=5)
      MyWorksheet.Sort(sortParams, 0, 0, 9, 5);
      // или: MyWorksheet.Sort(sortParams, 'A1:F10');
    end;

Поиск и замена

Модуль fpsSearch реализует поисковую систему , которая может использоваться для поиска определенного содержимого ячейки в рабочей книге или для замены найденного содержимого ячейки какой-либо другой строкой.

Например:

pascal
var
      MyWorkbook: TsWorkbook;
      MyWorksheet: TsWorksheet;
      MyRow, MyCol: Cardinal;
      MySearchParams: TsSearchParams;
    begin
      MyWorkbook := TsWorkbook.Create;
      try
        MyWorkbook.ReadFromFile(AFileName);
    
        // Specify search criteria
        MySearchParams.SearchText := 'Привет';
        MySearchParams.Options := [soEntireDocument];
        MySearchParams.Within := swWorkbook;
    
        // или: MySearchParaams := InitSearchParams('Привет', [soEntireDocument], swWorkbook);
    
        // Создать поисковую систему и выполнить поиск
        with TSearchEngine.Create(MyWorkbook) do begin
          if FindFirst(MySearchParams, MyWorksheet, MyRow, MyCol) then begin
            WriteLn('Первый [искомый текст] "', MySearchparams.SearchText, '" найден в ячейке ', GetCellString(MyRow, MyCol));
            while FindNext(MySeachParams, MyWorksheet, myRow, MyCol) do
              WriteLn('Следующий [искомый текст] "', MySearchParams.SearchText, '" найден в ячейке ', GetCellString(MyRow, MyCol));
          end;
          Free;
        end;
      finally
        MyWorkbook.Free;
      end;
    end;

Поисковая система предоставляет два метода для поиска : FindFirst иFindNext. Они очень похожи, но различаются только местом, где начинается поиск. В случае FindFirst начальная ячейка определяется [набором опций] из списка Options, описанных ниже. В случае FindNext поиск начинается в ячейке, следующей за предыдущей найденной ячейкой. Оба метода возвращают рабочий лист, [а также] индексы строк и столбцов ячейки, в которой найден искомый текст. Если поиск безуспешен, результат функции FALSE.

Запись TsSearchParams указывает критерии, используемые для поиска:

pascal
type
      TsSearchParams = record
        SearchText: String;
        Options: TsSearchOptions;
        Within: TsSearchWithin;
      end;

Помимо текста для поиска (SearchText), она предоставляет набор опций для сужения поиска:

Поле записи Within идентифицирует часть электронной таблицы для поиска:

Запись параметров поиска может быть инициализирована вызовом InitSearchParams (в модуле fpsutils) с элементами записи в качестве необязательных параметров.

В дополнение к поиску поисковая система также может использоваться для замены найденного текста другой строкой. Для этого вызовите функции ReplaceFirst или ReplaceNext. Они действуют как аналог [функции] FindXXXX, поэтому для определения критериев поиска требуется запись TsSearchParams. Но в дополнение к поиску эти функции также выполняют замену текста в соответствии со спецификацией в записи TsReplaceParams:

pascal
type
      TsReplaceParams = record
        ReplaceText: String;
        Options: TsReplaceOptions;
      end;

ReplaceText идентифицирует строку, которая заменит найденный шаблон текста. Параметры Options определяют набор критериев, по которым выполняется замена:

Используйте функцию InitReplaceParams (в модуле fpsutils) для инициализации записи параметров замены с предопределенными (но необязательными) значениями.

Операции со столбцами и строками

Рабочий лист предоставляет эти методы для вставки, удаления, скрытия или отображения столбцов и строк:

pascal
type
      TsWorksheet = class
      ...
        procedure DeleteCol(ACol: Cardinal);
        procedure DeleteRow(ARow: Cardinal);
    
        procedure InsertCol(ACol: Cardinal);
        procedure InsertRow(ARow: Cardinal);
    
        procedure RemoveCol(ACol: Cardinal);
        procedure RemoveRow(ARow: Cardinal);
    
        procedure RemoveAllCols;
        procedure RemoveAllRows
    
        procedure HideCol(ACol: Cardinal);
        procedure HideRow(ARow: Cardinal);
        
        procedure ShowCol(ACol: Cardinal);
        procedure ShowRow(ARow: Cardinal);
    
        function ColHidden(ACol: Cardinal): Boolean;
        function RowHidden(ARow: Cardinal): Boolean;

Макет страницы

Общие сведения

Пока что FPSpreadsheet не поддерживает печать рабочих листов, но приложения Office делают [это], и они предоставляют секцию информации в своих файлах для этой цели. В FPSpreadsheets эта информация доступна в классе TsPageLayout, который принадлежит структуре данных TsWorksheet. Его свойства и методы сочетают в себе самые важные функции из мира Excel и OpenDocument.

pascal
type 
      TsPageOrientation = (spoPortrait, spoLandscape);
    
      TsPrintOption = (poPrintGridLines, poPrintHeaders, poPrintPagesByRows,
        poMonochrome, poDraftQuality, poPrintCellComments, poDefaultOrientation,
        poUseStartPageNumber, poCommentsAtEnd, poHorCentered, poVertCentered,
        poDifferentOddEven, poDifferentFirst, poFitPages);
    
      TsPrintOptions = set of TsPrintOption;  
    
      TsHeaderFooterSectionIndex = (hfsLeft, hfsCenter, hfsRight);
    
      TsCellRange = record
        Row1, Col1, Row2, Col2: Cardinal;
      end;
    
      TsPageLayout = class
      ...
      public
        ...
        { Methods }
        // встроенные изображения заголовка/нижнего колонтитула
        procedure AddHeaderImage(AHeaderIndex: Integer;
          ASection: TsHeaderFooterSectionIndex; const AFilename: String);
        procedure AddFooterImage(AFooterIndex: Integer;
          ASection: TsHeaderFooterSectionIndex; const AFilename: String);
        procedure GetImageSections(out AHeaderTags, AFooterTags: String);
        function HasHeaderFooterImages: Boolean;
    
        // Повторитель строк и столбцов 
        function HasRepeatedCols: Boolean;
        function HasRepeatedRows: Boolean;
        procedure SetRepeatedCols(AFirstCol, ALastCol: Cardinal);
        procedure SetRepeatedRows(AFirstRow, ALastRow: Cardinal);
    
        // диапазоны печати 
        function AddPrintRange(ARow1, ACol1, ARow2, ACol2: Cardinal): Integer; overload;
        function AddPrintRange(const ARange: TsCellRange): Integer; overload;
        function GetPrintRange(AIndex: Integer): TsCellRange;
        function NumPrintRanges: Integer;
        procedure RemovePrintRange(AIndex: Integer);
    
        { Properties }
        property Orientation: TsPageOrientation read FOrientation write FOrientation;
        property PageWidth: Double read FPageWidth write FPageWidth;
        property PageHeight: Double read FPageHeight write FPageHeight;
        property LeftMargin: Double read FLeftMargin write FLeftMargin;
        property RightMargin: Double read FRightMargin write FRightMargin;
        property TopMargin: Double read FTopMargin write FTopMargin;
        property BottomMargin: Double read FBottomMargin write FBottomMargin;
        property HeaderMargin: Double read FHeaderMargin write FHeaderMargin;
        property FooterMargin: Double read FFooterMargin write FFooterMargin;
        property StartPageNumber: Integer read FStartPageNumber write SetStartPageNumber;
        property ScalingFactor: Integer read FScalingFactor write SetScalingFactor;
        property FitHeightToPages: Integer read FFitHeightToPages write SetFitHeightToPages;
        property FitWidthToPages: Integer read FFitWidthToPages write SetFitWidthToPages;
        property Copies: Integer read FCopies write FCopies;
        property Options: TsPrintOptions read FOptions write FOptions;
        property Headers[AIndex: Integer]: String read GetHeaders write SetHeaders;
        property Footers[AIndex: Integer]: String read GetFooters write SetFooters;
        property RepeatedCols: TsRowColRange read FRepeatedCols;
        property RepeatedRows: TsRowColRange read FRepeatedRows;
        property PrintRange[AIndex: Integer]: TsCellRange read GetPrintRange;
        property FooterImages[ASection: TsHeaderFooterSectionIndex]: TsHeaderFooterImage read GetFooterImages;
        property HeaderImages[ASection: TsHeaderFooterSectionIndex]: TsHeaderFooterImage read GetHeaderImages;
      end;
    
      TsWorksheet = class
      ...
      public
        property PageLayout: TsPageLayout;
        ...
      end;

Note-icon.png

Примечание: Тот факт, что PageLayout принадлежит рабочему листу, указывает на то, что в одной книге может быть несколько макетов страниц, по одному для каждого листа.

pascal
MyWorksheet.PageLayout.Options := MyWorksheet.PageLayout.Options + [poFitPages];
      MyWorksheet.PageLayout.FitWidthToPages := 1;     // все столбцы на ширине одной страницы
      MyWorksheet.PageLayout.FitHeightToPages := 0;    // использовать как можно больше страниц

Заголовки и колонтитулы

Текст заголовков и колонтитулов может состоять из выровненных по левому краю, центрированных и выровненных по правому краю строк. Добавьте символ &L, чтобы указать, что следующая строка должна быть напечатана с выравниванием слева; используйте &C соответственно для центрируемых [строк] и &R для [строк] с выравниванием по правому краю. Существуют другие символы, которые во время печати будут дополнять [действие символов]:

Массивы Headers[]/Footers[] предоставляют пространство для использования трех разных верхних и нижних колонтитулов:

Оставьте строки с индексом 0 и 2 пустыми, если в распечатке всегда должен быть один и тот же верхний/нижний колонтитул. Для большей ясности вы можете использовать константу HEADER_FOOTER_INDEX_ALL. Например:

pascal
MyWorksheet.PageLayout.Headers[HEADER_FOOTER_INDEX_ALL] := '&C&D &T';           // выровненный по центру заголовок "дата время" на всех страницах 
      MyWorksheet.PageLayout.Footers[HEADER_FOOTER_INDEX_ODD] := '&RPage &P of &N';   // выровненный  по правому краю нижний колонтитул на нечетных страницах "Страница .. из .." 
      MyWorksheet.PageLayout.Footers[HEADER_FOOTER_INDEX_EVEN] := '&LPage &P of &N';  // то же, но на четных страницах с выравниванием слева

Защита

В приложениях Office книги могут быть защищены от непреднамеренных изменений пользователем. fpspreadsheet способен читать и записывать структуры данных, связанные с защитой, но не применяет их. Это означает, например, что ячейки могут быть изменены пользователем, хотя рабочий лист указан как заблокированный.

Защита осуществляется на трех уровнях: защита рабочей книги, защита рабочего листа и защита элементов.

Защита рабочей книги

TsWorkbook содержит набор параметров защиты рабочей книги или документов:

В отношении защиты рабочей книги используется опция рабочего листа soPanesProtection, которая предотвращает изменение панелей рабочего листа, если рабочая книга защищена.

В зависимости от формата файла могут поддерживаться только некоторые из этих параметров. В этих случаях не поддерживаемые параметры являются общепринятыми значениями по умолчанию.

Защита рабочего листа

TsWorksheet содержит аналогичный набор параметров защиты. Всякий раз, когда опция включена в набор Protection рабочей книги, соответствующее действие не разрешено и заблокировано:

Эти уровни защиты становятся активными, если опция soProtected добавлена в [набор] Options рабочего листа или [посредством] вызова метода Protect(true) рабочего листа.

Защита ячейки

Защита ячеек становится активной, когда включена защита рабочего листа. Он управляется набором элементов TsCellProtection, которые принадлежат к формату ячейки:

Защита ячейки может быть изменена путем вызова метода WriteCellProtection рабочего листа. И наоборот, [свойство] ReadCellProtection может использоваться для извлечения состояния защиты конкретной ячейки:

pascal
// запрос и изменение состояния защиты ячейки A1 (строка=0, столбец=0)
    var
      cell: PCell;
      cellprot: TsCellProtections;
    ...
      // Находим ячейку
      cell := worksheet.FindCell(0, 0);
      // запрос защиты ячейки
      cellprot := worksheet.ReadCellProtection(cell);
      // Разблокировка ячейки для редактирования без изменения видимости формул
      worksheet.WriteCellProtection(cell, cellprot - [cpLockCell]);
      // Сокрытие формулы ячейки и разблокировка ячейки.
      worksheet.WriteCellProtection(cell, [cpHideFormulas]);

Защита

Защита рабочей книги и рабочего листа может быть обеспечена паролем. Обратите внимание, что эти пароли не шифруют файл (кроме защиты рабочей книги в Excel 2007). В приложениях Office пользователь должен ввести этот пароль, чтобы отключить защиту или изменить элементы защиты. Зашифрованный пароль хранится в записи CryptoInfo рабочей книги и рабочих листов соответственно:

pascal
type
      TsCryptoInfo = record
        PasswordHash: String;
        Algorithm: TsCryptoAlgorithm;  // caExcel, caSHA1, caSHA256, etc.
        SaltValue: String;
        SpinCount: Integer;
      end;

Warning-icon.png

Предупреждение: FPSpreadsheet не выполняет никаких расчетов хэширования, запись CryptoInfo просто передается от чтения до записи. Это вызывает проблемы, если при чтении и записи используются разные форматы файлов. Компонент пытается обнаружить несовместимые комбинации. В этих случаях защита паролем удаляется , и в рабочей книге записывается ошибка.

Загрузка и сохранение

Добавление новых форматов файлов

FPSpreadsheet открыт для любого формата файлов электронных таблиц. В дополнение к встроенным форматам файлов, которые указаны одной из деклараций sfXXXX, можно предоставить выделенные блоки чтения и записи для доступа к специальным форматам файлов.

pascal
function RegisterSpreadFormat(AFormat: TsSpreadsheetFormat; AReaderClass: TsSpreadReaderClass; AWriterClass: TsSpreadWriterClass;
      AFormatName, ATechnicalName: String; const AFileExtensions: array of String): TsSpreadFormatID;

Выбор потока

Рабочие книги загружаются и сохраняются с помощью методов ReadFromFile и WriteToFile, соответственно (или их потоковыми аналогами, ReadFromStream и WriteToStream).

По умолчанию доступ к файлам данных осуществляется с помощью "потока в памяти", что обеспечивает быстрый доступ к файлам. Однако в случае очень больших файлов (например, десятков тысяч строк) в системе может случиться нехватка памяти. Существует два способа отложить переполнение памяти в некоторой степени.

Виртуальный режим

Помимо использования временной памяти при чтении/записи потребление основной памяти происходит во внутренней структуре FPSpreadsheet, которая хранит все данные в памяти. Чтобы преодолеть это ограничение, был введен "виртуальный режим". В этом режиме данные принимаются из источника данных (например, таблицы базы данных) и передаются писателю без сбора на рабочем листе. Понятно, что данные, загруженные в виртуальный режим, не могут отображаться в визуальных элементах управления. Виртуальный режим хорош для преобразования между различными форматами данных.

Ряд шагов, необходимых для использования этого режима:

Виртуальный режим также работает для чтения файлов электронных таблиц.

В папке example/other содержится разработанный образец проекта, демонстрирующий виртуальный режим с использованием случайных данных. Более реалистичные примеры баз данных приведены в example/db_import_export и в главе преобразование большой таблицы базы данных с использованием виртуального режима.

Экспорт данных

FPC содержит набор модулей, которые позволяют экспортировать наборы данных в различные форматы (XML, SQL-запросы, DBF-файлы, ...). Существует основной пакет, который позволяет вам выбирать формат экспорта во время разработки или времени выполнения (пакет lazdbexport для Lazarus).

FPSpreadsheet имеет [свойство] TFPSExport, которое подключается к этой системе. Он позволяет экспортировать содержимое набора данных в файл новой электронной таблицы (.xls , .xlsx , .ods , формат wiki) с таблицей на первом листе по умолчанию. Кроме того, если MultipleSheets установлено значение TRUE, можно скомпоновать несколько листов в отдельные рабочие листы в том же файле. Вы можете дополнительно указать имена полей в качестве ячеек заголовка в первой строке, используя свойство HeaderRow в настройках экспорта. Компонент экспорта пытается найти формат номера ячеек в соответствии с типами полей набора данных.

Для более сложного экспорта вам необходимо вручную запрограммировать решение (см. примеры ниже), но для простой передачи данных/динамического экспорта по запросу пользователя этого модуля, вероятно, будет достаточно.

Простой пример того, как это работает:

pascal
uses
    ...
    fpsexport
    ...
    var
      Exp: TFPSExport;
      ExpSettings: TFPSExportFormatSettings;
      TheDate: TDateTime;
    begin
      FDataset.First; //предположим, что у нас есть набор данных FDataset
      Exp := TFPSExport.Create(nil);
      ExpSettings := TFPSExportFormatSettings.Create(true);
      try
        ExpSettings.ExportFormat := efXLS; // выбираем формат файла
        ExpSettings.HeaderRow := true; // включаем строку заголовка с именами полей
        Exp.FormatSettings := ExpSettings; // применяем настройки для экспорта объекта
        Exp.Dataset:=FDataset; // указываем источник
        Exp.FileName := 'c:\temp\datadump.xls';
        Exp.Execute; // запускаем экспорт
      finally
        Exp.Free;
        ExpSettings.Free;
      end;

Экспорт в DBF

Вы можете легко сохранить информацию из Excel в dbf. Вот пример из форума. Обратите внимание, что этот пример должен работать с кодировкой Win1251 по умолчанию. Чтобы получить дополнительную информацию, обратитесь к этой теме 1(http://forum.lazarus.freepascal.org/index.php/topic,41636.0.html)

pascal
procedure TForm1.ExportToDBF(AWorksheet: TsWorksheet; AFileName: String);
    var
      i: Integer;
      f: TField;
      r, c: Cardinal;
      cell: PCell;
    begin
      DbfGlobals.DefaultCreateCodePage := 1251; //кодировка по умолчанию dbf
      DbfGlobals.DefaultOpenCodePage := 1251; //кодировка по умолчанию dbf
      if Dbf1.Active then Dbf1.Close;
      if FileExists(AFileName) then DeleteFile(AFileName);
    
      Dbf1.FilePathFull := ExtractFilePath(AFileName);
      Dbf1.TableName := ExtractFileName(AFileName);
      Dbf1.TableLevel := 25;  // DBase IV: 4 - наиболее широко используется; или 25 = FoxPro поддерживает nfCurrency
      Dbf1.LanguageID := $C9; //русский язык по умолчанию
      Dbf1.FieldDefs.Clear;
      //ниже находятся поля в excel
      Dbf1.FieldDefs.Add('fam', ftString);
      //добавляем другие поля, которые вы хотите сохранить
    
      Dbf1.CreateTable;
      Dbf1.Open;
    
      for f in Dbf1.Fields do
        f.OnGetText := @DbfGetTextHandler;
    
      // Пропускаем строку 0, которая содержит заголовки
      for r := 1 to AWorksheet.GetLastRowIndex do begin
        Dbf1.Append;
        for c := 0 to Dbf1.FieldDefs.Count-1 do begin
          f := Dbf1.Fields[c];
          cell := AWorksheet.FindCell(r, c);
          if cell = nil then
            f.Value := NULL
          else
            case cell^.ContentType of
              cctUTF8String: f.AsString := UTF8ToCP1251(cell^.UTF8StringValue);
              cctNumber: f.AsFloat := cell^.NumberValue;
              cctDateTime: f.AsDateTime := cell^.DateTimeValue;
              else f.AsString := UTF8ToCP1251(AWorksheet.ReadAsText(cell));
            end;
        end;
        Dbf1.Post;
      end;
    end;
    
    //Эта процедура вызывается так, чтобы текст в ячейках мог корректно отображаться в сетке рабочего листа на форме, иначе отобразятся симовлы '?'
    procedure TForm1.DbfGetTextHandler(Sender: TField; var AText: string; DisplayText: Boolean);
    begin
      if DisplayText then
        AText := CP1251ToUTF8(Sender.AsString);
    end;

Визуальные элементы управления для FPSpreadsheet

Пакет 'laz_fpspreadsheet_visual' реализует серию элементов управления, которые имитируют создание визуальных графических приложений:

См. Учебник FPSpreadsheet: написание приложения для мини-таблиц для получения дополнительной информации и обучения, а также см. demo projects [, чтобы посмотреть] примеры применения этих компонентов.

Примеры

Чтобы создать проект, который использует библиотеку fpspreadsheet, добавьте пакет fpspreadsheet_pkg в проект Lazarus или добавьте корневой каталог fpspreadsheet к вашим параметрам компилятора, если используете другую IDE.

Модули

Весь пакет FPSpreadsheet состоит из нескольких модулей. Приложение электронной таблицы обычно "использует" следующие модули:

Следующие модули необходимы только изредка:

Все остальные модули, вероятно, не нужны на уровне приложений. В случае визуальных элементов управления spreadsheet необходимые модули обычно вставляются во время разработки автоматически.

Примеры Excel 5

Примечание: этот пример требует [наличия модулей] avglvltree.pas, lazutf8.pas, asiancodepagefunctions.inc, asiancodepages.inc и lconvencoding.pas ([расположенных] в _$(LazarusDir)\components\lazutils_ ), по крайней мере для fpspreadsheet транковой (для разработчиков) версии Лазаруса

pascal
{
    excel5demo.dpr
    
    Демонстрирует, как написать файл Excel 5.x, используя библиотеку fpspreadsheet
    
    Вы можете изменить выходной формат, изменив константу OUTPUT_FORMAT
    
    АВТОР: Felipe Monteiro de Carvalho
    }
    program excel5demo;
    
    {$mode delphi}{$H+}
    
    uses
      Classes, SysUtils, fpstypes, fpspreadsheet, fpsallformats, laz_fpspreadsheet;
    
    const 
      OUTPUT_FORMAT = sfExcel5;
    
    var
      MyWorkbook: TsWorkbook;
      MyWorksheet: TsWorksheet;
      MyFormula: TsRPNFormula;
      MyDir: string;
    begin
      // Инициализация
      MyDir := ExtractFilePath(ParamStr(0));
    
      // Создание рабочей книги
      MyWorkbook := TsWorkbook.Create;
      try
        MyWorksheet := MyWorkbook.AddWorksheet('My Worksheet');
    
        // Записываем некоторые номера ячеек
        MyWorksheet.WriteNumber(0, 0, 1.0);
        MyWorksheet.WriteNumber(0, 1, 2.0);
        MyWorksheet.WriteNumber(0, 2, 3.0);
        MyWorksheet.WriteNumber(0, 3, 4.0);
    
        // Записываем формулу E1 = A1 + B1
        MyWorksheet.WriteFormula(0, 4, 'A1+B1');
    
        // Создаем новый рабочий лист
        MyWorksheet := MyWorkbook.AddWorksheet('My Worksheet 2');
    
        // Записываем некоторые строки ячеек
        MyWorksheet.WriteText(0, 0, 'First');
        MyWorksheet.WriteText(0, 1, 'Second');
        MyWorksheet.WriteText(0, 2, 'Third');
        MyWorksheet.WriteText(0, 3, 'Fourth');
    
        // Сохраняем электронную таблицу в файл
        MyWorkbook.WriteToFile(MyDir + 'test' + STR_EXCEL_EXTENSION, OUTPUT_FORMAT);
      finally
        MyWorkbook.Free;
      end;
    end.

Открытие существующей таблицы

Чтобы открыть таблицу, указав конкретный формат для использования, задействуйте [процедуру] ReadFromFile с двумя параметрами:

pascal
MyWorkbook.ReadFromFile(AFileName, sfExcel5);

Также можно вызвать ReadFromFile только с одним параметром - именем файла. Тогда в книге будет использоваться расширение [на основе] автоматического определения формата файла. В случае неоднозначного расширения .xls (Excel 2-8) [механизм автодетектирования] просто попробует различные возможности до тех пор, пока не сработает. Хотя типичные шаблоны байтов отпечатков пальцев теперь проверяются, все же возможно, что исключение будет поднято для каждого неправильного формата, если он запускается из среды IDE во время разработки; это не происходит во время выполнения.

pascal
MyWorkbook.ReadFromFile(AFileName);

Запись электронной таблицы в файл на основе расширения

Подобно процедуре ReadFromFile, также существует процедура WriteToFile для определения типа электронной таблицы на основе суффикса имени файла. Она использует процедуру GetFormatFromFileName в коде предыдущего раздела, поэтому фактический код прост. Тем не менее, она всегда будет записывать файлы с заданным расширением, используя последний формат, который использует это расширение (например, файлы Excel .xls будут записаны как sfExcel8), поэтому, если вы хотите их записать в более раннем формате, то должны использовать базовую процедуру.

Как и выше, этот код исправляет модуль fpspreadsheet.pas.

pascal
procedure TsWorkbook.WriteToFile(const AFileName: string; const AOverwriteExisting: Boolean = False); overload;
    var SheetType: TsSpreadsheetFormat;
    begin
      if getFormatFromFileName(AFileName, SheetType) then
        WriteToFile(AFileName, SheetType, AOverwriteExisting)
      else raise Exception.Create(Format(
        '[TsWorkbook.WriteToFile] [Сделана] попытка сохранить электронную таблицу по расширению, но расширение %s недействительно.', [ExtractFileExt(AFileName)]));
    end;

Итерация по всем рабочим листам

pascal
var
      MyWorkbook: TsWorkbook;
      MyWorksheet: TsWorksheet;
      i: Integer;
    begin
      // Здесь загружаем MyWorkbook из файла или создаем его
     
      for i := 0 to MyWorkbook.GetWorksheetCount() - 1 do
      begin
        MyWorksheet := MyWorkbook.GetWorksheetByIndex(i);
        // Делаем что-нибудь с MyWorksheet
      end;

Итерация через ячейки

Первая идея - использовать простой цикл for-to :

pascal
var
      MyWorksheet: TsWorksheet;
      col, row: Cardinal;
      cell: PCell;
    begin
      for row:=0 to MyWorksheet.GetLastRowIndex do
        for col := 0 to MyWorksheet.GetLastColIndex do
        begin
          cell := MyWorksheet.FindCell(row, col);
          WriteLn(MyWorksheet.ReadAsUTF8Text(cell));
        end;
    end;

FindCell инициирует поиск ячейки независимо от ранее найденной ячейки. Ячейки, однако, организованы между собой в отсортированной древовидной структуре, и каждая ячейка "знает" своих предыдущих и следующих соседей. Более того, FindCell тратит время на поиск несуществующих ячеек в случае редко занятых рабочих листов. В общем, более эффективно использовать синтаксис for-in , который использует внутреннюю древовидную структуру с помощью специальных счетчиков. Обратите внимание, что существуют также специализированные счетчики для поиска по строкам, столбцам или диапазонам ячеек:

pascal
var
      MyWorksheet: TsWorksheet;
      cell: PCell;
    begin
      // Поиск по всем ячейкам
      for cell in Myworksheet.Cells do
        WriteLn(MyWorksheet.ReadAsText(cell));
    
      // Поиск только в столбце 0
      for cell in MyWorksheet.Cells.GetColEnumerator(0) do
        WriteLn(MyWorksheet.ReadAsText(cell));
    
      // Поиск только в строке 2
      for cell in MyWorksheet.Cells.GetRowEnumerator(2) do
        WriteLn(MyWorksheet.ReadAsText(cell));
    
      //Поиск только в диапазоне A1:C2 (строки 0..1, столбцы 0..2)
      for cell in MyWorksheet.Cells.GetRangeEnumerator(0, 0, 1, 2) do
        WriteLn(MyWorksheet.ReadAsText(cell));
    end;

Преобразование базы данных в электронную таблицу

Самое простое решение - использовать DatasetExport component (прим.перев: ссылка на компонент не корректна).

Если вам нужно больше контролировать процесс, используйте что-то вроде:

pascal
program db5xls;
     
    {$mode delphi}{$H+}
     
    uses
      Classes, SysUtils, 
      // добавить модули базы данных
      fpstypes, fpspreadsheet, fpsallformats;
     
    const OUTPUT_FORMAT = sfExcel5;
     
    var
      MyWorkbook: TsWorkbook;
      MyWorksheet: TsWorksheet;
      MyDatabase: TSdfDataset;
      MyDir: string;
      i, j: Integer;
    begin
      // Инициализация
      MyDir := ExtractFilePath(ParamStr(0));
     
      // Открываем базу данных
      MyDatabase := TSdfDataset.Create;
      MyDatabase.Filename := 'test.dat';
      // Добавляем здесь описание таблицы
      MyDatabase.Active := True;
    
      // Создаем электронную таблицу
      MyWorkbook := TsWorkbook.Create;
      MyWorksheet := MyWorkbook.AddWorksheet('My Worksheet');
     
      // Записываем имена полей
      for i := 0 to MyDatabase.Fields.Count - 1 do
        MyWorksheet.WriteText(0, i, MyDatabase.Fields[i].FieldName);
    
      // Записываем все ячейки в рабочий лист
      MyDatabase.First;
      j := 0;
      while not MyDatabase.EOF do
      begin
        for i := 0 to MyDatabase.Fields.Count - 1 do
          MyWorksheet.WriteText(j + 1, i, MyDatabase.Fields[i].AsString);
    
        MyDatabase.Next;
        Inc(j);
      end;
    
      // Закрываем базу данных
      MyDatabase.Active := False;
      MyDatabase.Free;
    
      // Сохраняем электронную таблицу в файл
      MyWorkbook.WriteToFile(MyDir + 'test' + STR_EXCEL_EXTENSION, OUTPUT_FORMAT);
      MyWorkbook.Free;
    end.

Преобразование большой таблицы базы данных в электронную таблицу с использованием виртуального режима

Note-icon.png

Примечание: Пример программы в [папке] examples\db_import_export демонстрирует использование виртуального режима для экспорта наборов данных в файлы электронных таблиц.

Мы хотим записать большую таблицу базы данных в файл электронной таблицы. Первая строка электронной таблицы - это отображение названий полей жирным шрифтом и серым фоном.

Обычно FPSpreadsheet загружает полное представление электронной таблицы в память, поэтому мы будем использовать виртуальный режим для минимизации использования памяти.

pascal
type
      TDataProvider = class;
    
    var
      MyWorkbook: TsWorkbook;
      MyWorksheet: TsWorksheet;
      MyDatabase: TSdfDataset;
      MyDir: string;
      MyHeaderTemplateCell: PCell;
      DataProvider: TDataProvider;
    
    // Внедрите TDataProvider здесь - см. ниже ...
    
    begin
      // Инициализация
      MyDir := ExtractFilePath(ParamStr(0));
     
      // Открываем базу данных
      MyDatabase := TSdfDataset.Create;
      try
        MyDatabase.Filename := 'test.dat';
        // Добавляем описание таблицы здесь
        MyDatabase.Active := True;
    
        // Создаем электронную таблицу
        MyWorkbook := TsWorkbook.Create;
        try
          MyWorksheet := MyWorkbook.AddWorksheet('My Worksheet');
    
          // Создаем шаблон ячейки для строки заголовка, мы хотим, 
          // чтобы заголовок [был начертан] жирным и на сером фоне
          // Шаблон ячейки может быть, где угодно, в рабочей книге, просто выберите ячейку A1.
          MyWorksheet.WriteFontStyle(0, 0, [fssBold]);
          MyWorksheet.WriteBackgroundColor(0, 0, scGray);
          // Нам понадобится эта ячейка снова и снова, поэтому давайте сохраним указатель на нее в переменной
          MyHeaderTemplateCell := MyWorksheet.Find(0, 0);
     
          // Входим в виртуальный режим
          MyWorkbook.Options := MyWorkbook.Options + [boVirtualMode];
    
          // Определяем количество столбцов - нам нужен столбец для каждого поля
          MyWorksheet.VirtualColCount := MyDatabase.FieldCount;
    
          // Определяем количество строк - нам нужна каждая запись, плюс 1 строка для заголовка
          MyWorksheet.VirtualRowCount := MyDatabase.RecordCount + 1;
    
          // Связываем обработчик событий, который передает данные из базы данных в "писатель" электронной таблицы
          MyWorksheet.OnWriteCellData := @DataProvider.WriteCellData;
    
          // Записываем все ячейки в файл Excel8
          // Данные, которые должны быть записаны, указаны в обработчике событий OnWriteCellData.
          MyWorkbook.WriteToFile(MyDir + 'test.xls', sfExcel8);
    
        finally
          // Освобождаем
          MyWorkbook.Free;
        end;
    
      finally
        // Закрываем базу данных и освобождаем ее
        MyDatabase.Active := False;
        MyDatabase.Free;
      end;
    
    end.

Осталось написать обработчик событий для OnWriteCellData. Для консольной программы выше мы устанавливаем конкретный класс поставщика данных (в визуальной программе обработчик событий также может быть методом любой формы):

pascal
type
      TDataProvider = class
        procedure WriteCellData(Sender: TsWorksheet; ARow, ACol: Cardinal; var AValue: variant; var AStyleCell: PCell);
      end;
    
    procedure TDataProvider.WriteCellData(Sender: TsWorksheet; ARow, ACol: Cardinal; AValue: variant; var: AStyleCell: PCell);
    begin
      // Сначала обработаем строку заголовка:
      if ARow = 0 then begin
        // Значение, которое должно быть записано в электронную таблицу, - это имя поля.
        AValue := MyDatabase.Fields[ACol].FieldName;
        // Форматирование определено в HeaderTemplateCell.
        AStyleCell := MyHeaderTemplateCell;
        //Перемещаемся на первую запись
        MyDatabase.First;
      end else begin
        // Значение, которое должно быть записано в электронную таблицу, является значением записи в поле, соответствующем столбцу.
        // Никаких особых требований к форматированию --> оставляем AStyleCell по умолчанию (nil).
        AValue := MyDatabase.Fields[ACol].AsVariant;
        // Передвигаем курсор базы данных, если было записано последнее поле записи
        if ACol = MyDatabase.FieldCount-1 then MyDatabase.Next;
      end;
    end;

Преобразование между двумя форматами электронных таблиц

pascal
program ods2xls;
     
    {$mode delphi}{$H+}
     
    uses
      Classes, SysUtils, 
      fpstypes, fpspreadsheet, fpsallformats, fpspreadsheet_pkg;
     
    const 
      INPUT_FORMAT = sfOpenDocument;
      OUTPUT_FORMAT = sfExcel8;
     
    var
      MyWorkbook: TsWorkbook;
      MyDir: string;
    begin
      // Инициализация
      MyDir := ExtractFilePath(ParamStr(0));
     
      // Преобразование электронной таблицы
      MyWorkbook := TsWorkbook.Create;
      try
        MyWorkbook.ReadFromFile(MyDir + 'test.ods', INPUT_FORMAT);
        MyWorkbook.WriteToFile(MyDir + 'test.xls', OUTPUT_FORMAT);
      finally
        MyWorkbook.Free;
      end;
    end.

Чтение и запись CSV-файлов

CSV-файлы (CSV = значения, разделенные запятыми) - это текстовые файлы без метаданных. Поэтому требуется дополнительная информация для правильного чтения записи из/в рабочий лист. Глобальная записьCSVParams предоставляет основные настройки для этой цели:

pascal
type
      CSVParams: TsCSVParams = record    // W = запись, R = чтение, RW = чтение/запись
        SheetIndex: Integer;             // W: Индекс листа, который должен быть записан
        LineEnding: TsCSVLineEnding;     // W: Спецификация для конца строки, который должен быть записан
        Delimiter: Char;                 // RW: Разделитель столбцов
        QuoteChar: Char;                 // RW: Символ для квотированного ([заключенного в двойные кавычки]) текста
        Encoding: String;                // RW: Кодировка файла
        DetectContentType: Boolean;      // R: попытка конвертации строк в типы контента 
        NumberFormat: String;            // W: если пустые записи чисел, как на листе; в противном случае используется этот формат
        AutoDetectNumberFormat: Boolean; // R: автоматически определяет десятичный/тысячный разделитель, используемый в числах
        TrueText: String;                // RW: Строка для логического TRUE
        FalseText: String;               // RW: Строка для логического FALSE
        FormatSettings: TFormatSettings; // RW: добавляет параметры для преобразования
      end;

Эта запись содержит поля, которые оцениваются как только для чтения, только для записи или для обоих - см. прилагаемые комментарии.

Общей ситуацией является чтение файла с использованием десятичного разделителя чисел, который отличается от десятичного разделителя системы: предположим, что вы находитесь в европейской системе, в которой десятичный разделитель является запятой, но файл csv, который должен быть прочитан, берется из машины, которая использует десятичную точку. Предположим также, что файл содержит символы табуляции в качестве разделителя столбцов вместо запятой по умолчанию. В этом случае просто установите CSVParams.FormatSettings.DecimalSeparator в '.', а CSVParams.Delimiter в #9 (символ TAB) перед чтением файла:

pascal
uses
      fpstypes, fpspreadsheet, fpscsv;
    var
      MyWorkbook: TsWorkbook;
    begin
      CSVParams.FormatSettings.DecimalSeparator := '.';
      CSVParams.Delimiter := #9;
      MyWorkbook := TsWorkbook.Create;
      try
        MyWorkbook.ReadFromFile('machine-data.csv', sfCSV);
      finally
        MyWorkbook.Free;
      end;
    end;

Note-icon.png

Примечание: Если вы хотите дать пользователю возможность интерактивного изменения записи CSVParams, посмотрите в [код] модуля scsvparamsform.pas демоверсии spready , который предоставляет готовый к использованию диалог.

Примеры проектов в папке установки fpspreadsheet

Установку FPSpreadsheet сопровождает куча проектов с примерами. Их можно найти в папке "examples". Вот краткое описание этих типовых проектов

Загрузка

Система контроля версий (Subversion)

Вы можете загрузить FPSpreadsheet с использованием приложений subversion и следующей командной строки:

pascal
svn checkout svn://svn.code.sf.net/p/lazarus-ccr/svn/components/fpspreadsheet fpspreadsheet

Журнал изменений SVN

Несовместимые изменения

Стабильные версии

Вы можете найти все выпуски FPSpreadsheet на sourceforge.

Version 1.10.1

Это последний стабильный релиз.

Change log (with respect to v1.8x)
Incompatible changes

Version 1.8

Change log (with respect to v1.6x)
Incompatible changes

Version 1.6

Change log (with respect to v1.4.x)
Incompatible changes

Version 1.4

Change log (with respect to v1.2.x)
Incompatible changes

Wiki documentation of old releases

This wiki page is work in progress and updated whenever a new feature is added; therefore, its state corresponds to the svn trunk version of the package. If you work with an older stable version please use these "historic" wiki versions:

Установка

Параметры компилятора

Вот список условных определений , которые могут быть активированы для настройки некоторых режимов работы пакетов и/или их компиляции с более старыми версиями Lazarus/FPC:

Все эти определения собираются во включенном файле fps.inc.

Поддержка и отчетность об ошибках

Рекомендуемое место для обсуждения FPSpreadsheet и получения поддержки [по интересующим вопросам находится тут] Lazarus Forum.

Отчеты об ошибках должны быть отправлены на Lazarus/Free Pascal Bug Tracker; пожалуйста, указывайте [с пометкой] проект "Lazarus-CCR".

Текущие достижения

Достижения в поддержке содержимого ячеек

Формат Несколько · страниц Поддержка · юникода Поддержка · чтения Поддержка · записи Текст Число Строковая · формула RPN · формула Ссылки · на 3D-ячейки Дата/Время Комментарии Гиперссылки Изображения +++ Защита
CSV files Нет Да + Работает ++ Работает ++ Работает ++ Работает ++ Недоступно Недоступно Недоступно Работает ++ Недоступно Недоступно Недоступно Недоступно
Excel 2.x Нет Нет * Работает ** Работает Работает Работает Работает Работает *** Недоступно Работает **** Работает Недоступно Недоступно Работает
Excel 5.0 (Excel 5.0 and 95) Да Нет * Работает ** Работает Работает Работает Работает Работает *** Работает Работает **** Работает Недоступно Недоступно Работает
Excel 8.0 (Excel 97- 2003) Да Да Работает ** Работает Работает Работает Работает Работает *** Работает Работает **** Только чтение Работает Не работает Работает
Excel OOXML Да Да Работает ** Работает Работает Работает Работает *** Работает Работает Работает **** Работает Работает Только запись Работает
OpenDocument Да Да Работает ** Работает Работает Работает Работает *** Работает Работает Работает **** Работает Работает Работает Работает
HTML Нет Да Работает ++ Работает ++ Работает ++ Работает ++ Недоступно Недоступно Недоступно Работает ++ Недоступно Работает Не работает Недоступно
Wikitable files (Mediawiki) Нет Да планируется Работает ++ Работает ++ Работает ++ Недоступно Недоступно Недоступно Работает ++ Недоступно Недоступно Не работает Недоступно

(+) Зависит от файла.
(++) Нет поддержки "true" формата чисел, поскольку файл не содержит информации о форматировании числа. Но числовой формат, используемый в настоящее время в электронной таблице, понятен.
(+++) Только очень простая поддержка изображений: без преобразований, без обрезки, без манипуляций с изображениями.
() В форматах, которые не поддерживают Unicode, данные сохраняются по умолчанию как ISO 8859-1 (Latin 1). Вы можете изменить кодировку в TsWorkbook.Encoding. Обратите внимание, что FPSpreadsheet предлагает процедуры чтения и записи [в кодировке] UTF-8, но данные могут быть преобразованы в ISO при чтении или записи на диск. Будьте осторожны, потому что символы, которые не соответствуют выбранной кодировке, будут потеряны в этих операциях. Замечания здесь применимы только для форматов, которые не поддерживают Unicode.
() Некоторые ячейки могут быть пустыми из-за отсутствующих или [до сих пор] не реализованных форматов чисел и текста.
(
) Это формат, в котором формулы записываются в файл (определяется дизайном формата файла).
(****) Поддерживается запись всех форматов. Однако некоторые редкие пользовательские форматы могут быть неправильно распознаны. BIFF2 в дизайне поддерживает только встроенные форматы.

Достижения опций форматирования

Доступны некоторые параметры форматирования:

Формат Выравнивание · текста Вращение · текста Шрифт Rich · text Границы Поддержка · цвета Задний · фон Перенос · слов Размер · столбца и строки Числовой · формат Слияние · ячеек Макет · страницы Печать · диапазонов Изображения · шапки/подвала · [таблицы] Формат · столбца/строки Скрытие · столбцов/строк
CSV files Недоступно Недоступно Недоступно Недоступно Недоступно Недоступно Недоступно Недоступно Недоступно Недоступно Недоступно Недоступно Недоступно Недоступно Недоступно Недоступно
Excel 2.x Работает* Недоступно Работает Недоступно Работает Работает Работает** Недоступно Работает Работает Недоступно Работает Недоступно Недоступно Работает Недоступно
Excel 5.0 · (Excel 5.0 and 95) Работает Работает Работает Работает Работает Работает Работает Работает Работает Работает Недоступно Работает Работает Недоступно Работает Работает
Excel 8.0 · (Excel 97 - XP) Работает Работает Работает Работает Работает Работает Работает Работает Работает Работает Работает Работает Работает Не работает Работает Работает
Excel OOXML (xlsx) Работает Работает Работает Работает Работает Работает Работает Работает Работает Работает Работает Работает Работает Только запись Работает Работает
OpenDocument Работает Работает Работает Работает Работает Работает Работает*** Работает Работает Работает Работает Работает Работает Работает Работает Работает
HTML (+) Работает баги Работает Работает баги Работает Работает **** Только запись Только запись Недоступно Работает Недоступно Недоступно Не работает Только запись предстоит сделать
Wikitable (Mediawiki) Только запись Недоступно Только запись Не работает Только запись Только запись Только запись Только запись Недоступно Только запись Недоступно Недоступно Не работает Только запись предстоит сделать

(Недоступно) Функционал недоступен для этого формата по существу.
() BIFF2 поддерживает только горизонтальное выравнивание текста, вертикальное выравнивание игнорируется.
() BIFF2 не поддерживает цвет фона; вместо этого используется черно-белый фон с пунктиром.
(
) OpenDocument поддерживает только однородные фоны; Вместо этого записывается цвет заливки, интерполированный между цветами переднего и заднего плана.
(****) Только однородный цвет фона, без стилей заполнения.
(+) HTML-ридер не поддерживает стили. Поскольку автор использует стили, эти файлы не считываются правильно.

Достижения [реализации] пользовательских интерфейсов рабочей книги/рабочего листа

Были добавлены дополнительные опции для интерфейса содержимого файла с помощью TsWorksheetGrid:

Формат Скрытие · линий сетки Скрытие · заголовков Заморозка · панелей Активный · лист/ячейка Масштабирование режим BiDi
Excel 2.x Работает Работает Не работает Недоступно Недоступно Недоступно
Excel 5.0 (Excel 5.0 and 95) Работает Работает Работает Работает Работает Недоступно
Excel 8.0 (Excel 97 - XP) Работает Работает Работает Работает Работает Работает
Excel OOXML Работает Работает Работает Работает Работает Работает
OpenDocument Работает Работает Работает Работает Работает Работает
HTML Только запись Только запись Недоступно Недоступно Недоступно Не работает

Список [запланированных] дел

Примечание: этот список является предварительным, поддерживается разработчиками и может меняться без предварительного уведомления. Если вы заинтересованы в содействии, пожалуйста, свяжитесь с нами и отправьте патч - спасибо!

Долгосрочные:

Changelog

Changes in the development version that have not yet been released are already documented on this page.

Version 1.10.1 bug fix release, based on revision 6598.

Version 1.10 release, based on svn revision 6547.

Version 1.8.3. Fixes compilation with Lazarus 1.8. New, highDPI-aware component palette icons

Version 1.8.2 , based on svn revision 5832. Fixes writing distorted images due to incorrect row height calculation.

Version 1.8 , based on svn revision 5781.

Version 1.6.2 released, based on svn revision 4619. Fixes integer overflow in formulas (Issue #29999).

Version 1.6 released, based on svn release 4106. Improved memory consumption, comments, hyperlinks, background fill patterns, cell enumerator, fraction number format, page layout, modified color management, offline wiki version included.

Version 1.4.3 released. Fixes formula calculation in worksheet grid.

Version 1.4.2 released. Fixes incomplete reading of ods files with repeated cells (Issue #0027389)

Version 1.4.1 released. A bugfix release for 1.4 that fixes incorrect streaming of TsWorksheetGrid and reading errors of biff5 and biff8 readers.

Version 1.4 released (based on subversion revision 3856 with full formula support, xlsx reader, csv reader and writer, wikitables writer, speed enhancement, virtual mode, db export component, row and column insertion/deletion, sorting, merged cells, visual controls in addition to (improved) fpspreadsheet grid.

Version 1.2.1 released. This is a bugfix release for 1.2 that fixes a bug in spreadsheetGrid (Issue #26521)

Version 1.2 released (based on subversion revision 3241) with fpsgrid improvements, date/time cell support for .xls, .ods, vastly improved cell formatting support, improved formula support, unit tests.

Version 1.1 released with all improvements up to revision 2621

Released version 1.0 , which includes OO XML generation support with bold formatting supported and also a lot of improvements from the last years

Implemented a cross-platform support for OLE file. Now Excel 5.0 files can be created in any operating system. Adds read support for Excel 2.1

Initial commit to lazarus-ccr with write support for Excel 2.1, Excel 5.0 (Windows only) and experimental OOXML and OpenDocument

Лицензия

LGPL с исключением статического связывания. Это та же лицензия, что и в библиотеке компонентов Lazarus.

Ссылки

Wiki ссылки

Внешние ссылки


From the Free Pascal wiki, page "FPSpreadsheet/ru", as the Internet Archive kept it on 2023-05-12, last changed on 2023-01-25. Copyright stays with the author who wrote it, according to the old wiki's Licensing page. If you have concerns about this material, message the admin.

Версия 1, последнее изменение: WikiArchive, .