FPSpreadsheet
│
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:
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 byAFormat
.
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 ifAOverwriteExisting
istrue
: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: 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
(forContentType=cctFormula
),RPNFormulaValue
(forContentType=cctRPNFormula
),NumberValue
(forContentType=cctNumber
),UTF8StringValue
(forContentType=cctUTF8String
), orDateTimeValue
(forContentType=cctDateTime
), orBoolValue
(forContentType=cctBool
), i.e.TRUE
orFALSE
, orErrorValue
(forContentType=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 listTextRotation
: specifies whether the cell text is written horizontally or verticallyHorAlignment
: left-aligned, horizontally centered, or right-aligned textVertAlignment
: top, buttom or vertically centered textBorder
: 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 theBorderStyles
.BackgroundColor
: Index into the workbook's color palette for the background color of the cell.NumberFormat
andNumberFormatStr
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 number3.141592654
becomes3.14
. - nfFixedTh: similar to
nfFixed
, but adds a thousand separator when the number is displayed as a string: The number3.141592654
would remain like in the previous example because it is too small to show thousand separators. But the number314159.2654
would become314,159.26
, for 2 decimals. - nfExp selects exponential presentation, i.e. splits off the exponent. The parameter
ADecimals
inWriteNumber
determines how many decimal places are used. (The number3.141592654
becomes3.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 number3.141592654
is displayed as314.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 toWriteCurrency
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 theDateSeparator
of the workbook'sFormatSettings
. - 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'sFormatFloat
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:
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: 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
, andfssUnderline
which form the enumeration typeTsFontStyle
. 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
- Microsoft OLE Document Format - http://sc.openoffice.org/compdocfileformat.pdf
- Excel file format description - http://sc.openoffice.org/excelfileformat.pdf
- Excel xls and PowerPoint ppt file dumper written in Python - very handy to list all contents of BIFF files (e.g. ./xls-dump.py file.xls) - http://cgit.freedesktop.org/libreoffice/contrib/mso-dumper/