FPSpreadsheet

From Lazarus wiki
Revision as of 11:09, 26 June 2014 by BigChimp (talk | contribs) (Support and Bug Reporting: bug obsolete due to release 1.2)

Deutsch (de) English (en) español (es) français (fr) polski (pl) русский (ru)

The fpSpreadsheet library offers a convenient way to generate and read spreadsheet documents in various formats. The library is written in a very flexible manner, capable of being extended to support any number of formats easily.

Screenshot of spready demo program provided with fpspreadsheet showing an XLS file: fpsgrid.png

API Documentation

API Reference

A help file in CHM format can be found in the fpspreadsheet installation root folder. If you did not yet install the package follow http://lazarus-ccr.svn.sourceforge.net/viewvc/lazarus-ccr/components/fpspreadsheet/fpspreadsheet.chm to "fpspreadsheet.chm".

Basics

The smallest entities in a spreadsheet are the cells which contain the data. Cells can hold various data types, like strings, numbers, dates, times, or formulas.

The cells are arranged in a grid-like structure, called worksheet, or spreadsheet, consisting of rows and columns. Each cell has a unique address given by the row and column index.

Worksheets are bound together to form a workbook which represents the document of the spreadsheet application.

fpspreadsheet follows this same structure - there is a TCell, a TsWorksheet, and a TsWorkbook.

Workbook

The class TsWorkbook is the main class visible to the user. It provides methods for reading data from and writing them to file. The versatile structure of the library provides access to various popular file formats, like Excel .xls or .xlsx, or OpenOffice .ods.

The file format is specified by the type TsSpreadsheetFormat

type
  TsSpreadsheetFormat = (sfExcel2, sfExcel5, sfExcel8, sfOOXML, 
    sfOpenDocument, sfCSV, sfWikiTable_Pipes, sfWikiTable_WikiMedia);

where sfExcel* stands for versions of the binary xls format used by Excel ("BIFF" = "Binary Interchange File Format"), sfOOXLM corresponds to the newer xlsx format introduced by Excel2007, and sfOpenDocument is the spreadsheet format used internally by OpenOffice/LibreOffice. There are no plans to implement "ancient" file formats like Excel3.0/4.0 or Lotus.

When applying fpspreadsheet the first task is to create an instance of the workbook:

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

Reading of spreadsheet files is accomplished (among others) by the workbook methods

  • procedure ReadFromFile(AFileName: string):
    Reads the file with the given name and automatically determines the correct file format.
  • procedure ReadFromFile(AFileName: string; AFormat: TsSpreadsheetFormat):
    Reads the file, but assumes that the file format is as specified by AFormat.

The following workbook methods can be used for saving to file:

  • procedure WriteToFile(const AFileName: string; const AFormat: TsSpreadsheetFormat; const AOverwriteExisting: Boolean = False):
    Writes the workbook to the given file using the given spreadsheet format. If the file already exists it is automatically overwritten if AOverwriteExisting is true:
  • procedure WriteToFile(const AFileName: String; const AOverwriteExisting: Boolean = False):
    dto., but the file format is determined from the file extension provided (in case of Excel's xls the most recent version, sfExcel8, is used).

Worksheet

The workbook contains a list of TsWorksheet instances. They correspond to the tabs that you see in Excel or Open/LibreOffice. When reading a spreadsheet file the worksheets are created automatically according to the file contents. When a spreadsheet is created manually to be stored on file a worksheet has to be created by adding it to the workbook:

var
  MyWorkbook: TsWorkbook;
  MyWorksheet: TsWorksheet;
begin
  MyWorkbook := TsWorkbook.Create;
  MyWorksheet := MyWorkbook.AddWorksheet('My_Table');  
    // 'My_Table' is the "name" of the worksheet
  ...

Already existing worksheets can be accessed by using the TsWorkbook methods

  • function GetFirstWorksheet: TsWorksheet: retrieves the first worksheet of the workbook.
  • function GetWorksheetByIndex(AIndex: Cardinal): TsWorksheet: returns the worksheet with the given index (starting at 0).
  • function GetWorksheetByName(AName: String): TsWorksheet: returns the worksheet with the given name which was used when the worksheet was added.

The count of already existing worksheets can be queried by calling GetWorksheetCount.

Cell

The worksheet, finally, gives access to the cells. A newly created worksheet, as in above example, is empty and does not contain any cells. Cells are added by assigning data or attributes to them by one of the WriteXXXX methods of the worksheet. As already mentioned, a cell is addressed by the index of the row and column to which it belongs. As usual, row and column indexes start at 0. Therefore, cell "A1" belongs to row 0 and column 0. It should be noted that row and column index are always specified in this order, this is different from the convention of TStringGrid. The following example creates a cell at address A1 and puts the number 1.0 in it.

var
  MyWorkbook: TsWorkbook;
  MyWorksheet: TsWorksheet;
begin
  MyWorkbook := TsWorkbook.Create;
  MyWorksheet := MyWorkbook.AddWorksheet('My_Table');
  MyWorksheet.WriteNumber(0, 0, 1.0);  // "A1" has row=0 and col=0
  ...

It is also possible to access cells directly by means of the methods FindCell(ARow, ACol) or GetCell(ARow, ACol) of the workbook. Please be aware that these functions return a pointer to the cell data (type PCell). Don't forget to dereference the pointers! The difference between FindCell and GetCell is that the former one returns nil, if a cell does not yet exist, while the latter one creates an empty cell in this case. This is the declaration of the cell's data type:

  TCell = record
    Col: Cardinal; // zero-based
    Row: Cardinal; // zero-based
    ContentType: TCellContentType;

    { Possible values for the cells }
    FormulaValue: TsFormula;
    RPNFormulaValue: TsRPNFormula;
    NumberValue: double;
    UTF8StringValue: ansistring;
    DateTimeValue: TDateTime;
    BoolValue: Boolean;
    ErrorValue: TsErrorValue;

    { Attributes, i.e. formatting fields }
    UsedFormattingFields: TsUsedFormattingFields;
    FontIndex: Integer;
    TextRotation: TsTextRotation;
    HorAlignment: TsHorAlignment;
    VertAlignment: TsVertAlignment;
    Border: TsCellBorders;
    BorderStyles: TsCelLBorderStyles;
    BackgroundColor: TsColor;
    NumberFormat: TsNumberFormat;
    NumberFormatStr: String;
  end;

  PCell = ^TCell;
Note-icon.png

Note: It is not recommended to manipulate the contents of TCell directly. Always use the corresponding WriteXXXX methods of the spreadsheet instead. The reason is that fpspreadsheet is under active development, and there is a large chance that the internal structure of TCell will change

The field ContentType indicates which data type is stored in the cell:

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

According to this field the corresponding data can be found in the fields

  • FormulaValue (for ContentType=cctFormula),
  • RPNFormulaValue (for ContentType=cctRPNFormula),
  • NumberValue (for ContentType=cctNumber),
  • UTF8StringValue (for ContentType=cctUTF8String), or
  • DateTimeValue (for ContentType=cctDateTime), or
  • BoolValue (for ContentType=cctBool), i.e. TRUE or FALSE, or
  • ErrorValue (for ContentType=cctError).

In addition to the data values, each cell contains a variety of attributes to be used for formatting:

  • FontIndex: text font by specifying the index in the workbook's font list
  • TextRotation: specifies whether the cell text is written horizontally or vertically
  • HorAlignment: left-aligned, horizontally centered, or right-aligned text
  • VertAlignment: top, buttom or vertically centered text
  • Border: a set of flags indicating if a border line is to be drawn at the left, top, right, or bottom cell edge. the lines are drawn according to the BorderStyles.
  • BackgroundColor: Index into the workbook's color palette for the background color of the cell.
  • NumberFormat and NumberFormatStr specify how number or date/time values are formatted (e.g., number of decimal places, long or short date format, etc.).

See cell formatting below for a more detailed description.

Formulas

Two kinds of formulas are supported by FPSpreadsheet:

  • String formulas: These are written in strings just like in the office application, for example "=ROUND(A1+B1,0)". They used in the files of Open/LibreOffice and Excel xlsx. Currently, string formulas can be read, but not calculated, from Open/LibreOffice files. Writing is not implemented, yet.
  • RPN formulas: These are written in Reverse Polish Notation (RPN), for example: A1, B1, Add, 0, ROUND, and can be found in the binary xls Excel files. Writing of RPN formulas is supported for the majority of Excel functions, automatic parsing of a string formula to create an RPN formula, however, is not possible, and the sequence of RPN tokens has to be created manually - see next section. FPSpreadsheet does read the RPN formula, but so far uses it only to create the string formula form the RPN tokens; the formula result is not calculated.

RPN Formulas

Understanding RPN formulas

RPN formulas are an intermediate result after parsing a string formula. They consist of tokens, i.e. information on the constituents of the formula in a way that can be immediately used for calculation of the expression result. There are tokens for numbers, operations, functions etc. When parsing, the tokens are extracted from the expression string and pushed onto a stack. In fpspreadsheet, this stack corresponds to the array TsRPNFormula, the array elements correspond to the tokens on the stack. When calculating the formula, Excel traverses the stack buttom-up (meaning in fpspreadsheet: from low- to high-index array elements). Whenever it finds a token for an operation or function it removes this token from the stack, along with the tokens of the operands, and replaces them by the result of the calculation.

Here's an example: In a simple expression like "=4+5", the stack contains the tokens for the number constants:

  • the first argument: [4]
  • the second argument: [5]
  • the operation [+].

The "+" operation is a binary operation, meaning that it needs two arguments. Therefore, when Excel reaches the [+] token, it removes the [+] and both operands from the stack and replaces them by the result of the calculation, the token with the value 9. Since there are no other elements on the stack, this is the final result of the calculation.

Now a more complex examples: "=ROUND(2+4*3.141592, 2)" which rounds the result of the calculation 2+4*3.141592 to two decimals. The function "ROUND" requires two parameters: the value to be rounded, and the number of decimal places. In total, the stack consists of these elements:

  • [2]
  • [4]
  • [3.141592]
  • [*]
  • [+]
  • [2]
  • [ROUND]

Going from first to last, the first operation/function token met is [*]. As this is another binary operation, this requires two arguments. Therefore, [4], [3.141592] and [*] are removed from the stack and replaced by the result [12.56637].

Now the stack looks like:

  • [2]
  • [12.56637]
  • [+]
  • [2]
  • [ROUND]

Now, the first operation token found is [+] replacing [2], [12.56637], [+] by [14.56637]. Finally, the stack is left with the tokens needed for the ROUND function:

  • [14.56637]
  • [2]
  • [ROUND]

which immediately leads to the final result [14.57].

Using simple constant numbers

For coding above formula "=4+5" in fpspreadsheet the length of the RPNFormula array must be set to 3 (3 elements, "4", "5", "+"). The first and second elements are "numbers" which has to be indicated by setting ElementKind=fekNum for these array elements. The value of each number is specified as the DoubleValue of the formula element. The last element is the formula which is specified by the ElementKind of fekAdd.

All in all, this results in the following code:

var
  MyRPNFormula: TsRPNFormula;
begin
  // Write the formula =4+5
  MyWorksheet.WriteUTF8Text(3, 0, '=4+5'); // A4
  // Write the RPN formula to the spreadsheet
  SetLength(MyRPNFormula, 3);
  MyRPNFormula[0].ElementKind := fekNum;
  MyRPNFormula[0].DoubleValue := 4.0;
  MyRPNFormula[1].ElementKind := fekNum;
  MyRPNFormula[1].DoubleValue := 5.0;
  MyRPNFormula[2].ElementKind := fekAdd;
  MyWorksheet.WriteRPNFormula(3, 2, MyRPNFormula);
end;

This requires quite some typing. For simplification a methodology of nested function calls has been added to fpspreadsheet in which every element is specified by a function which links to the next element function via its last argument:

begin
  // Write the formula =4+5
  MyWorksheet.WriteUTF8Text(3, 0, '=4+5');
  // Write the RPN formula to the spreadsheet
  MyWorksheet.WriteRPNFormula(3, 2,  // Row and column of the formula cell
    CreateRPNFormula(                // function to create a compact RPN formula
      RPNNumber(4,                   // 1st operand: a number with value 4
      RPNNumber(5,                   // 2nd operand: a number with value 5
      RPNFunc(fekAdd,                // function to be performed: add
      nil)))));                      // end of list
end;

Using cells in formulas

Of course, the formulas can also contain links to cells. For this purpose the ElementType needs to be fekCellValue. This instructs Excel to use the value of the cell in the calculation. There are, however, also functions which require other properties of the cell, like format or address. For this case, use fekCellRef for the ElementKind. Another specialty is the usage of absolute and relative cell addresses ($A$1 vs. A1, respectively). Cell row and column addresses specified in the RPNFormula elements are absolute by default. If you want relative rows/columns add rfRelRow or rfRelCol to the element's RelFlags set. Or, if you prefer the nested function notation simply use the function RPNCellValue (or RPNCellRef) with the standard notation of the cell adress using the $ sign.

Here, as an example, =A1*$B$1 in array notation:

var
  MyRPNFormula: TsRPNFormula;
begin
  SetLength(MyRPNFormula, 3);
  MyRPNFormula[0].ElementKind := fekCellValue;
  MyRPNFormula[0].Row := 0;   // A1
  MyRPNFormula[0].Col := 0;
  MyRPNFormula[0].RelFlags := [rfRelRow, rfRelCol];  // relative!
  MyRPNFormula[1].ElementKind := fekCellValue;
  MyRPNFormula[1].Row := 1;
  MyRPNFormula[1].Col := 0;   // $B$1, RelFlags not needed since absolute address
  MyRPNFormula[2].ElementKind := fekMul;
  MyWorksheet.WriteRPNFormula(3, 2, MyRPNFormula);
end;

And now in nested function notation:

  MyWorksheet.WriteRPNFormula(3, 2,  // Row and column of the formula cell
    CreateRPNFormula(                // function to create a compact RPN formula
      RPNCellValue('A1',             // 1st operand: contents of cell "A1" (relative!)
      RPNCellValue('$B$1',           // 2nd operand: contents of cell "$B$1" (absolute!)
      RPNFunc(fekMul,                // function to be performed: multiply
      nil)))));                      // end of list

Using ranges of cells

In spreadsheet applications like Excel, the notation A1:C5 refers to a range of cells: the rectangle between (and including) cells A1 and C5.

This feature is available in fpspreadsheet as well: use the ElementKind fekCellRange and a second set of row/column indices (Row2 and Col2, respectively). There are also flags rfRelRow2 and rfRelCol2 to mark the second corner cell as relative.

Using built-in operations and functions

Here is a list of the basic operations available in fpspreadsheet RPN formulas:

ElementKind Example Meaning Operands Argument types Argument function
fekAdd =A1+A2 add numbers 2 fekNum, fekCellValue RPNNumber(), RPNCellValue()
fekSub =A1-A2 subtract numbers 2 fekNum, fekCellValue RPNNumber(), RPNCellValue()
fekMul =A1*A2 multiply numbers 2 fekNum, fekCellValue RPNNumber(), RPNCellValue()
fekDiv =A1/A2 divide numbers 2 fekNum, fekCellValue RPNNumber(), RPNCellValue()
fekPercent =A1% divide a number by 100 and add "%" sign 1 fekNum, fekCellValue RPNNumber(), RPNCellValue()
fekPower =A1^2 power of two numbers 2 fekNum, fekCellValue RPNNumber(), RPNCellValue()
fekUMinus =-A1 unary minus 1 fekNum, fekCellValue RPNNumber(), RPNCellValue()
fekUPlus =+A1 unary plus 1 fekNum, fekCellValue RPNNumber(), RPNCellValue()
fekConcat ="Hello "&A1 string concatenation 2 fekString, fekCellValue RPNString(), RPNCellValue()

Column "Operands" indicates how many operands are required on the stack before the function.

Beyond that, Excel provides a huge number of functions, many of which have been made available for fpspreadsheet via a corresponding ElementKind. Please note that some functions allow a variable count of parameters. In this case, this value has to be specified as ParamsNum in the formula.

The following table is far from complete. To learn about the functions available, look at the declaration of TFEKind in fpspreadsheet.pas which hints at the name of the Excel function. Also have a look at the file "rpntests.inc" in the tests folder of the fpspreadsheet installation where every function is included with an example.

ElementKind Example Meaning Operands Argument types Argument function
fekABS =ABS(A1) absolute value of number 1 fekNum, fekCellValue RPNNumber(), RPNCellValue()
fekSIN =SIN(A1) sine of a number 1 fekNum, fekCellValue RPNNumber(), RPNCellValue()
fekLOG =LOG(A1) logarithm of a number 2 fekNum, fekCellValue RPNNumber(), RPNCellValue()
fekPI =PI() returns pi() 0 -
fekDATE =DATE(2014,4,9) constructs date from parts 3 fekNum, fekCellValue RPNNumber(), RPNCellValue()
fekTIME =TIME(8,0,0) constructs time from parts 3 fekNum, fekCellValue RPNNumber(), RPNCellValue()
fekCOUNT =COUNT(A1:B5) count non-empty cells var (specify!) fekCellRef, fekCellRange RPNCellRef(), RPNCellRange()
fekSUM =SUM(A1:B5) sum of cells var (specify!) fekCellRef, fekCellRange RPNCellRef(), RPNCellRange()
fekAND =AND(A1,B1) logical AND 2 fekBool, fekCellValue RPNBool(), RPNCellValue
fekLOWER =LOWER(A1) converts string to lower-case 1 fekString, feCellValue RPNString(), RPNCellValue()

Here is an example which calculates the logarithm of cell A1:

  SetLength(MyRPNFormula, 2);
  MyRPNFormula[0].ElementKind := fekNum;
  MyRPNFormula[0].Row := 0;   // A1
  MyRPNFormula[0].Col := 0;
  MyRPNFormula[0].RelFlags := [rfRelRow, rfRelCol];
  MyRPNFormula[1].ElementKind := fekLOG;
  MyWorksheet.WriteRPNFormula(1, 2, MyRPNFormula);  // cell C2

or, in compact writing:

  MyRPNFormula.WriteRPNFormula(1, 2, CreateRPNFormula(
    RPNCellValue('A1',
    RPNFunc(fekLOG,         
    nil))));

The next example instructs Excel to calculate the sum of the cell range $A1:C$10. The function SUM accepts up to 30 parameters, therefore usage of a single parameter has to be specified explicitly in this case.

  SetLength(MyRPNFormula, 2);
  MyRPNFormula[0].ElementKind := fekCellRange;
  MyRPNFormula[0].Row := 0;   // $A1
  MyRPNFormula[0].Col := 0;
  MyRPNFormula[0].Row2 := 9;  // C$10
  MyRPNFormula[0].Col2 := 2;
  MyRPNFormula[0].RelFlags := [rfRelRow, rfRelCol2];
  MyRPNFormula[1].ElementKind := fekSUM;
  MyRPNFormula[1].ParamsNum := 1;      // 1 argument used in SUM
  MyWorksheet.WriteRPNFormula(1, 2, MyRPNFormula);  // cell C2

or, shorter:

  MyRPNFormula.WriteRPNFormula(1, 2, CreateRPNFormula(
    RPNCellRange('$A1:C$10',
    RPNFunc(fekSUM, 1,        // SUM with 1 argument
    nil))));

Remarks

Currently, RPN formulas are implemented for the xls file formats (sfExcel2, sfExcel5, sfExcel8), but mainly for writing. This means that Excel, when opening the file, will calculate the formula and display its result. If, however, the written file is opened by fpspreadsheet the calculation will not be performed and the formula field will be empty.

When you read an xls file containing formulas you can construct the formula string which Excel had used for construction of the RPN formula by calling the method ReadRPNFormulaAsString of the worksheet.

Cell formatting

Number and date/time formats

Numbers and date/time values can be displayed in a variety of formats. In fpspreadsheet this can be achieved in two ways:

  • using built-in number formats by specifiying a value for the NumberFormat of the cell
  • using a custom format string.

Number formats can be specified by these worksheet methods:

type
  TsWorksheet = class
  public
    // Set number formats alone
    procedure WriteNumberFormat(ARow, ACol: Cardinal; ANumberFormat: TsNumberFormat;
      const AFormatString: String = ''); overload;
    procedure WriteNumberFormat(ACell: PCell; ANumberFormat: TsNumberFormat;
      const AFormatString: String = ''); overload;  

    // Set cell values and number formats in one call

    // number values
    procedure WriteNumber(ARow, ACol: Cardinal; ANumber: double;
      AFormat: TsNumberFormat = nfGeneral; ADecimals: Byte = 2;
      ACurrencySymbol: String = ''); overload;
    procedure WriteNumber(ACell: PCell; ANumber: Double; AFormat: TsNumberFormat = nfGeneral;
      ADecimals: Byte = 2; ACurrencySymbol: String = ''); overload;
    procedure WriteNumber(ARow, ACol: Cardinal; ANumber: double;
      AFormat: TsNumberFormat; AFormatString: String); overload;
    procedure WriteNumber(ACell: PCell; ANumber: Double;
      AFormat: TsNumberFormat; AFormatString: String); overload;   

    // date/time values
    procedure WriteDateTime(ARow, ACol: Cardinal; AValue: TDateTime;
      AFormat: TsNumberFormat = nfShortDateTime; AFormatStr: String = ''); overload;
    procedure WriteDateTime(ACell: PCell; AValue: TDateTime;
      AFormat: TsNumberFormat = nfShortDateTime; AFormatStr: String = ''); overload;
    procedure WriteDateTime(ARow, ACol: Cardinal; AValue: TDateTime;
      AFormatStr: String); overload;
    procedure WriteDateTime(ACell: PCell; AValue: TDateTime;
      AFormatStr: String); overload;  

    // currency values
    procedure WriteCurrency(ARow, ACol: Cardinal; AValue: Double;
      AFormat: TsNumberFormat = nfCurrency; ADecimals: Integer = 2;
      ACurrencySymbol: String = '?'; APosCurrFormat: Integer = -1;
      ANegCurrFormat: Integer = -1); overload;
    procedure WriteCurrency(ACell: PCell; AValue: Double;
      AFormat: TsNumberFormat = nfCurrency; ADecimals: Integer = -1;
      ACurrencySymbol: String = '?'; APosCurrFormat: Integer = -1;
      ANegCurrFormat: Integer = -1); overload;
    procedure WriteCurrency(ARow, ACol: Cardinal; AValue: Double;
      AFormat: TsNumberFormat; AFormatString: String); overload;
    procedure WriteCurrency(ACell: PCell; AValue: Double;
      AFormat: TsNumberFormat; AFormatString: String); overload;     
  ...

The built-in formates are defined by the enumeration TsNumberFormat. In spite of its name, the elements cover both number and date/time values:

type
  TsNumberFormat = (
    // general-purpose for all numbers
    nfGeneral,
    // numbers
    nfFixed, nfFixedTh, nfExp, nfPercentage,
    // currency
    nfCurrency, nfCurrencyRed, 
    // dates and times
    nfShortDateTime, nfShortDate, nfLongDate, nfShortTime, nfLongTime,
    nfShortTimeAM, nfLongTimeAM, nfTimeInterval,
    // other (using format string)
    nfCustom);
  • nfGeneral corresponds to the default formatting showing as many decimals as possible (the number 3.141592654 would be unchanged.)
  • nfFixed limits the decimals. The number of decimal places has to be specified in the call to WriteNumber. Example: with 2 decimals, the number 3.141592654 becomes 3.14.
  • nfFixedTh: similar to nfFixed, but adds a thousand separator when the number is displayed as a string: The number 3.141592654 would remain like in the previous example because it is too small to show thousand separators. But the number 314159.2654 would become 314,159.26, for 2 decimals.
  • nfExp selects exponential presentation, i.e. splits off the exponent. The parameter ADecimals in WriteNumber determines how many decimal places are used. (The number 3.141592654 becomes 3.14E+00 in case of two decimals).
  • nfPercentage displays the number as a percentage. This means that the value is multiplied by 100, and a percent sign is added. Again, specify in ADecimals how many decimal places are to be shown. (The number 3.141592654 is displayed as 314.92%, in case of 2 decimals).
  • nfCurrency displays the number together with a currency symbol, and there are special rules how to display negative values (in brackets, or minus sign before or after the number). The FormatSettings of the workbook are used to define the currency sign and the way numbers are displayed (FormatSettings.CurrencyString for the currency symbol, FormatSettings.CurrencyFormat for positive, FormatSettings.NegCurrFormat for negative values). These settings can be overridden by specifying them in the call to WriteCurrency directly.
  • nfCurrendyRed like nfCurrency, in addition negative values are displayed in red.
  • nfShortDateTime presents the DateTimeValue of the cell in "short date/time format", i.e. days + two digit months + two digit year + hours + minutes, no seconds. The order of the date parts is taken from the workbook's FormatSettings. This applies also to the other date/time formats.
  • nfShortDate creates a date string showing day + two-digit month + two-digit year
  • nfShortTime creates a time string showing hours + minutes.
  • nfLongTime, similar, but includes seconds as well
  • nfShortTimeAM, similar to nfShortTime, but uses the AM/PM time format, i.e. hours go up to 12, and AM or PM is added to specify morning or evening/afternoon.
  • nfLongTimeAM, like nfShortTimeAM, but includes seconds
  • nfTimeInterval, like nfLongTime, but there can be more than 24 hours. The interval can also be expressed in minutes or seconds, if the format strings [n]:ss, or [s], respectively, are used.
  • nfCustom allows to specify a dedicated formatting string.

As already noted the workbook has a property FormatSettings which provides additional information to control the resulting formatting. This is essentially a copy of the DefaultFormatSettings< declared in the sysutils unit (the elements LongDateFormat and ShortDateFormat are slightly modified to better match the default settings in the main spreadsheet applications). The main purpose of the FormatSettings is to add a simple way of localization to the number formats.

In addition to these pre-defined formats, more specialized formatting can be achieved by using the format constant nfCustom along with a dedicated format string. The format string is constructed according to the syntax of fpc's FormatFloat and FormatDateTime commands (see the online-help for these functions).

Here are two examples:

  • A date/time cell is to be displayed such that it shows only "month" (full name) and "year" (2 digits); in this case the format string would be
       mmmm/yy
    Note that the slash character (/) will be replaced by the DateSeparator of the workbook's FormatSettings.
  • A number cell should use the exponential format with three decimal places and at least two digits in the exponent for positive numbers. For negative numbers and the zero value, the text "not defined" should be shown:
       0.000E+00;"not defined";"not defined"
    (it is a little-known feature of fpc's FormatFloat function that the format string can be separated by semicolons into sections applied to positive, negative and zero values).

Colors

FPSpreadsheet supports colors for text and for cell background. The color is specified by means of an index (type TsColor) into a palette. There are descriptive constants for the indexes into the default palette, but the numerical value can be used as well:

DefaultPalette.png
const
  scBlack = $00;
  scWhite = $01;
  scRed = $02;
  scGreen = $03;
  scBlue = $04;
  scYellow = $05;
  scMagenta = $06;
  scCyan = $07;
  scDarkRed = $08;
  scDarkGreen = $09;
  scDarkBlue = $0A;    scNavy = $0A;
  scOlive = $0B;
  scPurple = $0C;
  scTeal = $0D;
  scSilver = $0E;
  scGrey = $0F;        scGray = $0F;       // redefine to allow different kinds of writing
  scGrey10pct = $10;   scGray10pct = $10;
  scGrey20pct = $11;   scGray20pct = $11;
  scOrange = $12;
  scDarkbrown = $13;
  scBrown = $14;
  scBeige = $15;
  scWheat = $16;

In addition to the default palette, there are other palettes which are predefined in the units xlsbiff2, xlsbiff5, and xlsbiff8, PALETTE_BIFF2, PALETTE_BIFF5, PALETTE_BIFF8, respectively. The following code shows how to replace the current palette of the worksheet by PALETTE_BIFF8:

  MyWorksheet.UsePalette(@PALETTE_BIFF8, Length(PALETTE_BIFF8));

The palette entries are of type TsColorValue which is a synonym for DWord. They contain color rgb values given in little-endian byte order which is compatible with TColor of the graphics unit. Use the procedure MakeLEPalette(APalette: PsPalette; APaletteSize: Integer) to convert a "big-endian" type of byte-order to the required format. The color rgb value can be queried by calling GetPaletteColor(ColorIndex: TsColor). The following code snippet fills the background of a series of cells with a color which has the same index as the corresponding row; additionally the color name is displayed in the neighboring cell (correct only when the default palette is used); in this way a list of all available colors can be created:

  for i:=0 to MyWorkbook.GetPaletteSize-1 do begin
    MyWorksheet.WriteBlank(i, 0);
    Myworksheet.WriteBackgroundColor(i, 0, TsColor(i));
    MyWorksheet.WriteUTF8Text(i, 1, MyWorkbook.GetColorName(i));
  end;

The file created by this code is loaded into Excel and displayed above.

Palette items can be modified by calling SetPaletteColor. The following example replaces the color with index 10 by the color value $00123456

  MyWorksheet.SetPaletteColor(10, $00123456);
Note-icon.png

Note: You must be aware that the color names given above may lose their meaning after changing the default palette.
The various file formats have limitations in palette size: BIFF2 supports only 16 colors which cannot be changed. BIFF5 and BIFF8 allow up to 64 colors, the upper 56 can be modified by the user.

Cell background color

Call the worksheet method WriteBackgroundColor to set the color of a given cell. As described above, the color is specified by the index into the color palette of the workbook. The background color is used in a solid fill of the cell rectangle, other fill patterns are not supported. Note also that background colors are lost when saving in BIFF2 format (sfExcel2) and replaced by a shaded background pattern.

type
  TsWorksheet = class
  public
    procedure WriteBackgroundColor(ARow, ACol: Cardinal; AColor: TsColor);
    // ...
  end;

  // Example: set background color of cell A1 (row 0, column 0) to gray
  MyWorksheet.WriteBackgroundColor(0, 0, clSilver);

Cell borders

Cells can be emphasized by drawing border lines along their edges. There are four borders enumerated in the data type TsCellBorder:

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

In order to show a border line add the corresponding border to the cell's set Borders (type TsCellBorders, see above). In this way, each cell edge can be handled separately. Use the worksheet method WriteBorders for this purpose. This example adds top and bottom borders to the edges A1 and B1:

  MyWorksheet.WriteBorders(0, 0, [cbNorth, cbSouth]);  // A1: row 0, column 0
  MyWorksheet.WriteBorders(0, 1, [cbNorth, cbSourth]); // B1: row 0, column 1

Borders usually are drawn as thin, solid, black lines. But it is possible to modify line style and color of each border line. For this purpose, the cell provides an array of TsCellBorderStyle records:

type
  TsCellBorderStyle = record
    LineStyle: TsLineStyle;    // (lsThin, lsMedium, lsDashed, lsDotted, lsThick, lsDouble)
    Color: TsColor;
  end;

  TsCellBorderStyles = array[TsCellBorder] of TsCellBorderStyle;   

  TsWorksheet = class
  public
    procedure WriteBorderStyle(ARow, ACol: Cardinal; ABorder: TsCellBorder;
      AStyle: TsCellBorderStyle); overload;
    procedure WriteBorderStyle(ARow, ACol: Cardinal; ABorder: TsCellBorder;
      ALineStyle: TsLineStyle; AColor: TsColor); overload;

    procedure WriteBorderColor(ARow, ACol: Cardinal; ABorder: TsCellBorder; AColor: TsColor);
    procedure WriteBorderLineStyle(ARow, ACol: Cardinal; ABorder: TsCellBorder;
      ALineStyle: TsLineStyle);
    procedure WriteBorderStyles(ARow, ACol: Cardinal; const AStyles: TsCellBorderStyles);      

    procedure WriteBorders(ARow, ACol: Cardinal; ABorders: TsCellBorders);
    // ...
  end;

The style of a given cell border can be specified by the following methods provided by the worksheet:

  • WriteBorderStyle assigns a cell border style record to one border of the cell. There are two overloaded versions of this method: one takes an entire TsCellBorderStyle record, the other one takes the individual record elements.
  • WriteBorderColor changes the color of a given border without affecting the line style of this border.
  • WriteBorderLineStyle sets the line style of the border only, but leaves the color unchanged.
  • WriteBorderStyles sets the border style of all borders of a given cell at once. Useful for copying border styles from one cell to other cells.

This example adds a thin black border to the top, and a thick blue border to the bottom of cells A1 and B1:

  MyWorksheet.WriteBorders(0, 0, [cbNorth, cbSouth]);    // cell A1: row 0, column 0
  MyWorksheet.WriteBorderStyle(0, 0, lsThin, scBlack);  
  MyWorksheet.WriteBorderStyle(0, 0, lsThick, scBlue);

  MyWorksheet.WriteBorders(0, 1, [cbNorth, cbSouth]);    // cell B1: row 0, column 1
  MyWorksheet.WriteBorderStyles(0, 1, MyWorksheet.FindCell(0, 0).BorderStyles); 
    // copy border styles from cell A1 to B1

Fonts

The cell text can displayed in various fonts. For this purpose, the workbook provides a list of TsFont items:

type
  TsFont = class
    FontName: String;
    Size: Single;   
    Style: TsFontStyles;
    Color: TsColor;
  end;
  • The font name corresponds to the name of the font as used by the operational system. In Windows, an example would be "Times New Roman".
  • The font size is given in "points", i.e. units 1/72 inch which are commonly used in Office applications.
  • The font style is a set of the items fssBold, fssItalic, fssStrikeout, and fssUnderline which form the enumeration type TsFontStyle. The "normal" font corresponds to an empty set.
  • The color, finally, is an index into the workbook's color palette discussed above and determines the foreground color of the text characters.

Every cell is provided with an index into the font list.

In order to assign a particular font to a cell, use one of the following methods of TsSpreadsheet:

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;
  • WriteFont assigns a font to the cell. If the font does not yet exist in the font list a new entry is created. The function returns the index of the font in the font list. In addition, there is an overloaded version which only takes the font index as a parameter.
  • WriteFontColor replaces the color of the font that is currently assigned to the cell by a new one. Again, a new font list item is created if the font with the new color does not yet exist. The function returns the index of the font in the list.
  • WriteFontSize replaces the size of the currently used font of the cell.
  • WriteFontStyle replaces the style (normal, bold, italic, etc.) of the currently used cell font.

The workbook's font list contains at least one item which is the default font for cells with unmodified fonts. By default, this is 10-point "Arial". Use the workbook method SetDefaultFont to assign a different font to the first list item.

The font at a given index of the font list can be looked up by calling the workbook function GetFont. The count of available fonts is returned by GetFontCount.

Here is an example which decreases the size of all 10-point "Arial" fonts to 9-point:

var
  cell: PCell;
  font: TsFont;
begin
  cell := MyWorksheet.GetFirstCell;
  while cell <> nil then begin
    font := MyWorkbook.GetFont(cell^.FontIndex);
    if (font.FontName = 'Arial') and (font.Size = 10.0) then
      MyWorksheet.WriteFontSize(cell^.Row, cell^.Col, 9.0);
      // Don't modify font.Size directly because this will not update the font list!
    cell := MyWorksheet.GetNextCell;
  end;
end;

Text rotation

Usually text is displayed in the cells horizontally. However, it is also possible to rotate it by 90 degrees in clockwise or counterclockwise directions. In addition, there is also an option the stack horizontal characters vertically above each other.

If you need this feature use the worksheet method WriteTextRotation and specify the text direction by an element of the enumeration type TsTextRotation:

type
  TsTextRotation = (trHorizontal, rt90DegreeClockwiseRotation,
    rt90DegreeCounterClockwiseRotation, rtStacked);

  TsWorksheet = class
  public
    procedure WriteTextRotation(ARow, ACol: Cardinal; ARotation: TsTextRotation);
    // ...
  end;

  // example for counter-clockwise rotated text in cell A1:
  WriteTextRotation(0, 0, rt90DegreeCounterClockwizeRotation);

Please be aware that finer degrees of rotation which may be supported by some spreadsheet file formats are ignored.

Text alignment

By default, cell texts are aligned to the left and bottom edges of the cell, except for numbers which are right-aligned. This behavior can be changed by using the worksheet methods WriteHorAlignment and WriteVertAlignment:

type
  TsHorAlignment = (haDefault, haLeft, haCenter, haRight);
  TsVertAlignment = (vaDefault, vaTop, vaCenter, vaBottom);    

  TsWorkbook = class
  public
    procedure WriteHorAlignment(ARow, ACol: Cardinal; AValue: TsHorAlignment);
    procedure WriteVertAlignment(ARow, ACol: Cardinal; AValue: TsVertAlignment); 
    // ...
  end;

  // Example: Center the text in cell A1 both horizontally and vertically
  MyWorkbook.WriteHorAlignment(0, 0, haCenter);
  MyWorkbook.WriteVertAlignment(0, 0, vaCenter);

Word wrap

Text which is longer than the width of a cell can wrap into several lines by calling the method WriteWordwrap of the spreadsheet:

type
  TsWorksheet = class
  public
    procedure WriteWordwrap(ARow, ACol: Cardinal; AValue: Boolean);
    //...
  end;

  // Example: activate wordwrap in cell A1
  MyWorksheet.WriteWordwrap(0, 0, true);

Packages

FPSpreadsheet comes with the following packages to facilitate its usage with:

laz_fpspreadsheet.lpk

Adds all necessary files to use fpspreadsheet in your Lazarus projects. After adding this package as a requirement to your project you can add "fpspreadsheet" to the uses clause of the units which use it.

laz_fpspreadsheet_visual.lpk

Adds a set of visual components which expands the capabilities of FPSpreadsheet to also include editing and displaying data on screen inside LCL applications.

The following LCL components are installed with this package:

Examples

To create a project which uses the fpspreadsheet library, add the fpspreadsheet_pkg package to it's Lazarus project, or add the base directory of fpspreadsheet to you compiler options if using another IDE.

Excel 5 example

Note: at least with fpspreadsheet from trunk (development version), this example requires (at least) Lazarus avglvltree.pas, lazutf8.pas, asiancodepagefunctions.inc, asiancodepages.inc and lconvencoding.pas (in the $(LazarusDir)\components\lazutils\ directory)

{
excel5demo.dpr

Demonstrates how to write an Excel 5.x file using the fpspreadsheet library

You can change the output format by changing the OUTPUT_FORMAT constant

AUTHORS: Felipe Monteiro de Carvalho
}
program excel5demo;

{$mode delphi}{$H+}

uses
  Classes, SysUtils, fpspreadsheet, fpsallformats, fpspreadsheet_pkg;

const OUTPUT_FORMAT = sfExcel5;

var
  MyWorkbook: TsWorkbook;
  MyWorksheet: TsWorksheet;
  MyFormula: TsRPNFormula;
  MyDir: string;
begin
  // Initialization
  MyDir := ExtractFilePath(ParamStr(0));

  // Create the spreadsheet
  MyWorkbook := TsWorkbook.Create;
  MyWorksheet := MyWorkbook.AddWorksheet('My Worksheet');

  // Write some number cells
  MyWorksheet.WriteNumber(0, 0, 1.0);
  MyWorksheet.WriteNumber(0, 1, 2.0);
  MyWorksheet.WriteNumber(0, 2, 3.0);
  MyWorksheet.WriteNumber(0, 3, 4.0);

  // Write the formula E1 = A1 + B1
  // or, in RPN: A1, B1, +
  SetLength(MyFormula, 3);
  MyFormula[0].ElementKind:=fekCell; {A1}
  MyFormula[0].Col := 0;
  MyFormula[0].Row := 0;
  MyFormula[1].ElementKind:=fekCell; {B1}
  MyFormula[1].Col := 1;
  MyFormula[1].Row := 0;
  MyFormula[2].ElementKind:=fekAdd;;  {+}
  MyWorksheet.WriteRPNFormula(0, 4, MyFormula);

  // Creates a new worksheet
  MyWorksheet := MyWorkbook.AddWorksheet('My Worksheet 2');

  // Write some string cells
  MyWorksheet.WriteUTF8Text(0, 0, 'First');
  MyWorksheet.WriteUTF8Text(0, 1, 'Second');
  MyWorksheet.WriteUTF8Text(0, 2, 'Third');
  MyWorksheet.WriteUTF8Text(0, 3, 'Fourth');

  // Save the spreadsheet to a file
  MyWorkbook.WriteToFile(MyDir + 'test' + STR_EXCEL_EXTENSION, OUTPUT_FORMAT);
  MyWorkbook.Free;
end.

Opening an existing spreadsheet

To open a spreadsheet while specifying a particular format to use use ReadFromFile with two parameters:

MyWorkbook.ReadFromFile(AFileName, sfExcel5);

If ReadFromFile is called with only one parameter then it will use the extension to auto-detect the file format. In case of ambiguous formats like Excel 2-8 it will simply try various possibilities until one works. In the future it might make a more efficient check for the Excel format.

MyWorkbook.ReadFromFile(AFileName);

Writing a spreadsheet to file based on extension

Similar to the ReadFromFile routine, I've implemented a WriteToFile procedure (also with suggestions and enhancements from Felipe Monteiro de Carvalho) to determine the spreadsheet's type based on the filename suffix. It uses the getFormatFromFileName routine in the previous section's code, so the actual code is simple. However, it will always write files with a given extension using the latest format that uses that extension (e.g. Excel .xls files will be written as sfExcel8), so if you want to write them in an earlier format, you have to use the base routine.

As above, this code patches the fpspreadsheet.pas unit.

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] Attempted to save a spreadsheet by extension, but the extension %s is invalid.', [ExtractFileExt(AFileName)]));
end;

Iterating through all Worksheets

var
  MyWorkbook: TsWorkbook;
  MyWorksheet: TsWorksheet;
  i: Integer;
begin
  // Here load MyWorkbook from a file or build it
 
  for i := 0 to MyWorkbook.GetWorksheetCount() - 1 do
  begin
    MyWorksheet := MyWorkbook.GetWorksheetByIndex(i);
    // Do something with MyWorksheet
  end;

Converting a database to a spreadsheet

Use something like:

program db5xls;
 
{$mode delphi}{$H+}
 
uses
  Classes, SysUtils, 
  // add database units
  fpspreadsheet, fpsallformats;
 
const OUTPUT_FORMAT = sfExcel5;
 
var
  MyWorkbook: TsWorkbook;
  MyWorksheet: TsWorksheet;
  MyDatabase: TSdfDataset;
  MyDir: string;
  i, j: Integer;
begin
  // Initialization
  MyDir := ExtractFilePath(ParamStr(0));
 
  // Open the database
  MyDatabase := TSdfDataset.Create;
  MyDatabase.Filename := 'test.dat';
  // Add table description here
  MyDatabase.Active := True;

  // Create the spreadsheet
  MyWorkbook := TsWorkbook.Create;
  MyWorksheet := MyWorkbook.AddWorksheet('My Worksheet');
 
  // Write the field names
  for i := 0 to MyDatabase.Fields.Count - 1 do
    MyWorksheet.WriteUTF8Text(0, i, MyDatabase.Fields[i].FieldName);

  // Write all cells to the worksheet
  MyDatabase.First;
  j := 0;
  while not MyDatabase.EOF do
  begin
    for i := 0 to MyDatabase.Fields.Count - 1 do
      MyWorksheet.WriteUTF8Text(j + 1, i, MyDatabase.Fields[i].AsString);

    MyDatabase.Next;
    Inc(j);
  end;

  // Close the database
  MyDatabase.Active := False;
  MyDatabase.Free;

  // Save the spreadsheet to a file
  MyWorkbook.WriteToFile(MyDir + 'test' + STR_EXCEL_EXTENSION, OUTPUT_FORMAT);
  MyWorkbook.Free;
end.

Converting between two spreadsheet formats

Note that this is only meta-code, not tested.

program ods2xls;
 
{$mode delphi}{$H+}
 
uses
  Classes, SysUtils, 
  fpspreadsheet, fpsallformats, fpspreadsheet_pkg;
 
const 
  INPUT_FORMAT = sfOpenDocument;
  OUTPUT_FORMAT = sfExcel8;
 
var
  MyWorkbook: TsWorkbook;
  MyDir: string;
begin
  // Initialization
  MyDir := ExtractFilePath(ParamStr(0));
 
  // Convert the spreadsheet
  MyWorkbook := TsWorkbook.Create;
  try
    MyWorkbook.ReadFromFile(MyDir + 'test.ods', INPUT_FORMAT);
    MyWorkbook.WriteToFile(MyDir + 'test.xls', OUTPUT_FORMAT);
  finally
    MyWorkbook.Free;
  end;
end.

Grid and Charting Controls with FPSpreadsheet

See TsWorksheetGrid and TsWorksheetChartSource

Download

Subversion

You can download FPSpreadsheet using the subversion software and the following command line:

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

To do list

Note: this list is provisional, maintained by developers and can change without notice. If you are interested in contributing, please feel free to get in touch and submit a patch - thanks!

  • Formula support for OOXML (see bug Issue #25104)
  • Formula support for Opendocument (see bug Issue #25104)
  • Background colour support for OOXML (see bug Issue #25104)
  • Calculation of RPN formulas
  • Support for merged cells
  • Overflowing cell text in fpSpreadsheetGrid
  • Find out why BIFF2 files are corrupt when saved with frozen rows/cols activated.
  • Add row and column formats

Long-term:

  • Provide a more common user interface to fpspreadsheet (setter/getter and properties instead of Read*/Write* methods, MyWorksheet.Cells[ARow, ACol]), make TCell a class, avoid the pointers PCell.
  • Store formatting in a format list of the workbook, not in the cell, to reduce memory usage.
  • Use BIFF8 file-wide string storage instead of storing strings in cells (should reduce memory usage in case of many duplicate strings)
  • Add an fpspreadsheetexport unit similar to fpdbfexport

Subversion changelog

These changes have been implemented in the trunk/development version but have not yet been released. Once a release has been made, please move the documentation to the relevant locateion in this wiki article.

  • none


Latest release

One can find the latest release in sourceforge:

https://sourceforge.net/projects/lazarus-ccr/files/FPSpreadsheet/

Installation

  • If you only need non-GUI components: in Lazarus: Package/Open Package File, select laz_fpspreadsheet.lpk, click Compile. Now the package is known to Lazarus (and should e.g. show up in Package/Package Links). Add it to your project like you add other packages.
  • If you also want GUI components (grid and chart): Package/Open Package File, select laz_fpspreadsheet_visual.lpk, click Compile, then click Use, Install and follow the prompts to rebuild Lazarus with the new package. Drop needed grid/chart components on your forms as usual

Support and Bug Reporting

The recommended place to discuss FPSpreadsheet and obtain support is asking in the Lazarus Forum: http://www.lazarus.freepascal.org/index.php/board,42.0.html

Bug reports should be sent to the Lazarus/Free Pascal Bug Tracker; please specify the "Lazarus-CCR" project: http://bugs.freepascal.org/

Current Progress

Support by file format

Progress by supported format:

Format Multiple sheet support Unicode support Reader Progress Writer Progress Text Number String Formula RPN Formula Date/Time
Excel 2.x No No** Working Working Working Working Not implemented Working Working ***
Excel 5.0 (Excel 5.0 and 95) Yes No** Working* Working Working Working Not implemented Working Working ***
Excel 8.0 (Excel 97- 2003) Yes Yes Working* Working Working Working Not implemented Working Working ***
Microsoft OOXML Yes Yes Not implemented Working Working Working Not implemented Not implemented Not implemented
OpenDocument Yes Yes Working Working Working Working Not implemented Not implemented Working ***

(*) Some cell could be returned blank due missing or non ready implemented number and text formats.
(**) In formats which don't support Unicode the data is stored by default as ISO 8859-1 (Latin 1). You can change the encoding in TsWorkbook.Encoding. Note that FPSpreadsheet offers UTF-8 read and write routines, but the data might be converted to ISO when reading or writing to the disk. Be careful that characters which don't fit selected encoding will be lost in those operations. The remarks here are only valid for formats which don't support Unicode.
(***) Writing of all formats is supported. Some rare custom formats, however, may not be recognized correctly. BIFF2 supports only built-in formats by design.

Progress of the formatting options

Quite some formatting options are available:

Format Text align Text rotation Font Bold Border Color support Word-wrap Col&Row size Number format
Excel 2.x Working (vertical: N/A) N/A Working Working Working Working (*) N/A Working Working
Excel 5.0 (Excel 5.0 and 95) Working Working Working Working Working Working Working Working Working
Excel 8.0 (Excel 97 - XP) Working Working Working Working Working Working Working Working Working
Microsoft OOXML Not implemented Not implemented Not implemented Working Not implemented Not implemented Not implemented Not implemented Not implemented
OpenDocument Working Working Working Working Working Working Working Working Working

(*) BIFF2 does not support a background color.

Progress of workbook/worksheet user-interface options

Some additional options were added to interface the file contents with the fpSpreadsheetGrid:

Format Hide grid lines Hide headers Frozen Panes
Excel 2.x Working Working not working
Excel 5.0 (Excel 5.0 and 95) Working Working Working
Excel 8.0 (Excel 97 - XP) Working Working Working
Microsoft OOXML Not implemented Not implemented Not implemented
OpenDocument Working Working Working

Changelog

For changes in the development version that have not yet been released, please see Subversion changelog

June 2014

  • 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.

Jan 2013

  • Version 1.1 released with all improvements up to revision 2621

Nov 2011

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

Jan 2009

  • 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

Feb 2008

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

License

LGPL with static linking exception. This is the same license as is used in the Lazarus Component Library.

See also

External Links