Sign in Join
Wiki copytemporary

FPSpreadsheet/es: what changed

Revision 2 to 3. Removed lines have a minus sign; added lines have a plus sign.

OldNewLine
11El contenido que sigue a continuación es una traducción de la versión en inglés como fuente primaria, por lo que ante la duda aconsejo visitar esa página. Procuraré manter el contenido actualizado/sincronizado. Ultima fecha edición 21/septiembre/2016.
22
33La librería fpSpreadsheet ofrece un modo práctico de generar y leer documentos spreadsheet (hosas de cálculo) en varios formatos. Está escrita en una manera muy flexible, capaz de ser extendida para soportar cualquier número de formatos facilmente.
44
55Aquí se muestra un pantallazo del programa de demo "spready" que viene con fpspreadsheet, que muestra un fichero XLS.
66
77![](/wiki-images/b/b7/Fpsgrid.png)
88
99## Documentación
1010
1111Esta página wiki cubre las últimas versión de desarrollo/trunk de FPSpreadsheet disponibles vía subversin. Por favor mira la sección Stable releases para la documentación de la versión estable que puedes descargar.
1212
1313## Documentación API
1414
1515### Referencia de la API
1616
1717Hay disponible un fichero de ayuda en formato CHM dentro de la carpeta *docs* al descomprimir el paquete descargado (e.g. \fpspreadsheet-1.6.2\docs). Si todavía no has instalado el paquete sigue: [<http://lazarus-ccr.svn.sourceforge.net/viewvc/lazarus-ccr/components/fpspreadsheet/docs/fpspreadsheet-api.chm>](http://lazarus-ccr.svn.sourceforge.net/viewvc/lazarus-ccr/components/fpspreadsheet/docs/fpspreadsheet-api.chm) para *fpspreadsheet-api.chm*.
1818
1919Hay también disponible un segundo fichero CHM de ayuda en la misma carpeta *docs*, *fpspreadsheet-wiki.chm*, que es una instantanea de las páginas wiki relativas a FPSpreadsheet.
2020
2121### Conceptos básicos
2222
2323Las entidades más pequeñas en un spreadsheet son las **cells** (celdas), las cuales contienen datos. Las celdas (Cells) pueden contener varios tipos de datos, tales como cadenas, números, fechas, horas, valores booleanos o fórmulas. Adicionalmente, las celdas pueden contener información de formato, i.e. estilo de fuente, color de fondo, alineación de texto, etc.
2424
2525Las celdas están dispuestas en una estructura a modo de cuadrícula o rejilla llamada **worksheet**, or **spreadsheet** consistente en **rows** (filas) y **columns** (columnas). Cada celda tiene una dirección única dada por el índice de fila y columna.
2626
2727Las Worksheets (hojas del libro de trabajo) se ponen juntas para formar un **workbook** (libro de trabajo), el cual representa el documento de la aplicación spreadsheet (hoja de cálculo). El workbook almacena además la información de todos los worksheets, i.e. listado de fuentes, listados de formato de número, etc.
2828
2929FPSpreadsheet sigue la misma estructura - hay un `TCell`, un `TsWorksheet`, y un `TsWorkbook`.
3030
3131#### Workbook
3232
3333La clase `TsWorkbook` es la clase principal visible para el usuario. Provee métodos de lectura y escritura a ficheros. La estructura versátil de la librería provee acceso a una variedad de formatos de fichero populares tales como Excel *.xls* o *.xlsx*, así como de OpenOffice/LibreOffice *.ods*.
3434
3535El formato de fichero se especifica mediante el tipo `TsSpreadsheetFormat` definido en la unit `fpstypes`
3636
3737``` pascal
3838type
3939 TsSpreadsheetFormat = (sfExcel2, sfExcel5, sfExcel8, sfExcelXML, sfOOXML,
4040 sfOpenDocument, sfCSV, sfHTML, sfWikiTable_Pipes, sfWikiTable_WikiMedia, sfUser);
4141```
4242
4343Donde:
4444
4545- `sfExcel2, sfExcel5, sfExcel8` soporta versiones del formato binario xls utilizado por Excel ("BIFF" = "Binary Interchange File Format / Formato de Fichero de Intercambio Binario") siendo `sfExcel8` el más moderno.
4646- `sfOOXLM` Corresponde al formato más actual xlsx introducido para Excel2007.
4747- `sfExcelXML` es el formato xml que fué introducido por Microsoft con Office XP/2003. No muy popular.
4848- `sfOpenDocument` es el formato spreadsheet utilizado por OpenOffice/LibreOffice.
4949- `sfCSV` referido a ficheros de texto conteniendo valores delimitados por comas; es entendido por cualquier editor de texto y por todos los programas de hojas de cálculo (spreadsheet), pero no contienen información de formateado.
5050- `sfHTML` denota el formato estandar HTML tal como se utiliza en visores web.
5151- `sfWikiTable_Pipes` y `sfWikiTable_WikiMedia` es el formato utilizado por las tablas de los sitios web en formato wiki.
5252- `sfUser` se necesita para registrar un formato definido por el usuario. No hay planes de implementar formatos de fichero antiguos tales como Excel3.0/4.0 o Lotus. Es posible sin embargo aportar tus propias clases de lectura y escritura para extender la funcionalidad de FPSpreadsheet - Ver la sección más abajo sobre Añadiendo nuevos formatos de fichero
5353
5454Cuando se aplica un fpspreadsheet la primera tarea es crear una instancia de **workbook**:
5555
5656``` pascal
5757var
5858 MyWorkbook: TsWorkbook;
5959begin
6060 MyWorkbook := TsWorkbook.Create;
6161 ...
6262```
6363
6464La lectura de ficheros spreadsheets se realiza (entre otros) por los siguientes métodos de **workbook**:
6565
6666- `procedure ReadFromFile(AFileName: string):`\
6767 Lee el fichero especificado y determina automáticamente su formato correcto.
6868- `procedure ReadFromFile(AFileName: string; AFormat: TsSpreadsheetFormat):`\
6969 Lee el fichero, pero asume que su formato viene especificado en `AFormat`.
7070
7171Se pueden utilizar los siguientes métodos de workbook para salvar a fichero:
7272
7373- `procedure WriteToFile(const AFileName: string; const AFormat: TsSpreadsheetFormat; const AOverwriteExisting: Boolean = False)`:\
7474 Escribe un **workbook** al fichero dado utilizando el formato dado a spreadsheet. En caso de que el fichero ya exista entonces se sobreescribe automáticamente si `AOverwriteExisting` vale `true`:
7575- `procedure WriteToFile(const AFileName: String; const AOverwriteExisting: Boolean = False)`:\
7676 mismo, pero el formato de fichero se determina a partir de la extensión dada (en el caso de Excel con extensión xls y para la versión más reciente se utiliza `sfExcel8`).
7777
7878Después de llamar a estos métodos es conveniente revisar la propiedad `ErrorMsg` de workbook para verificar si existen mensajes de error o advertencias generadas durante el proceso de lectura o escritura. Esta propiedad retorna cadenas multi-línea por lo que se mostrarán mejor en un componente tipo memo; en caso de que el proceso de lectura o escritura se realice correctamente entonces nos retornará una cadena vacía.
7979
8080Note: FPSpreadsheets provee units especializadas para la lectura / escritura de cada formato de fichero. Estas unidades no se aplican automáticamente, deben ser añadidas explícitamente a la claúsula uses. FPSpreadsheet will complain about "unsupported file format" si no encuentra la lectura / escritura solicitada. Aquí se muestra un listado de los nombres de las units.
8181
8282- *xlsbiff2*, *xlsbiff5* y *xlsbiff8* para el formato de fichero binario correspondiente a xls `sfExcel2`, `sfExcel5` y `sfExcel8`, respectivamente,
8383- *xlsOOXML* para el formato de fichero xlsx `sfOOXML` o Excel 2007 y posteriores,
8484- *xlsXML*para el formato de fichero xml de Excel XP/2003,
8585- *fpsopendocument* para el formato de fichero `sfOpenDocument` de OpenOffice/LibreOffice,
8686- *fpsCSV* para ficheros de texto con valores separados por comas (csv),
8787- *fpsHTML* para fichero HTML,
8888- *wikitables* para `sfWikiTable_Pipes` y `sfWikiTable_WikiMedia`,
8989- o, simplemente añade *fpsallformats* para tener soporte de lectura / escritura para todos los tipos de formato soportados.
9090
9191#### Worksheet
9292
9393El workbook contiene un listado de instancias `TsWorksheet`. Estas corresponde con las solapas (tabs) que puedes ver en Excel o en OpenOffice/LibreOffice. Cuando se realiza la lectura de un fichero spreadsheet (hoja de cálculo) entonces se crean automáticamente las hojas del libro (worksheets) de acuerdo al contenido del fichero. Cuando se crea una hoja de cálculo manualmente para guardarlo en un fichero, entonces hay que crear un worksheet añadiendolo al libro:
9494
9595``` pascal
9696var
9797 MyWorkbook: TsWorkbook;
9898 MyWorksheet: TsWorksheet;
9999begin
100100 MyWorkbook := TsWorkbook.Create;
101101 MyWorksheet := MyWorkbook.AddWorksheet('My_Table');
102102 // 'My_Table' is the "name" of the worksheet
103103 ...
104104```
105105
106106Already existing worksheets can be accessed by using the `TsWorkbook` methods
107107
108108- `function GetFirstWorksheet: TsWorksheet`: retrieves the first worksheet of the workbook.
109109- `function GetWorksheetByIndex(AIndex: Cardinal): TsWorksheet`: returns the worksheet with the given index (starting at 0).
110110- `function GetWorksheetByName(AName: String): TsWorksheet`: returns the worksheet with the given name which was used when the worksheet was added.
111111
112112La cuenta de los worksheets que contiene se puede consultar llamando a `GetWorksheetCount`.
113113
114114#### Celda (cell)
115115
116116El worksheet, finalmente, permite acceder a las celdas. Un worksheet creado de cero, como en el ejemplo mostrado, se encuentra vacío y no contiene celdas. Las celdas se añaden mediante la asignación de datos o atributos utilizando métodos `WriteXXXX` del worksheet. Como ya se ha mencionado, la celda "A1" pertenece a la fila 0, columna 0 (row 0, col 0). Debe tenerse en cuenta que el índice de fila y columna siempre se especifican en este orden, lo cual es "diferente de la convención de" `TStringGrid`. El siguiente ejemplo crea una celda en la dirección A1 y le asigna el número `1.0`.
117117
118118``` pascal
119119var
120120 MyWorkbook: TsWorkbook;
121121 MyWorksheet: TsWorksheet;
122122begin
123123 MyWorkbook := TsWorkbook.Create;
124124 MyWorksheet := MyWorkbook.AddWorksheet('Mi_Tabla');
125125 MyWorksheet.WriteNumber(0, 0, 1.0); // "A1" tiene row=0 y col=0
126126 ...
127127```
128128
129129Además es posible acceder a las celdas directamente por medio de los métodos `FindCell(ARow, ACol)` o `GetCell(ARow, ACol)` del workbook. Ambas funciones existen además en la versión overloaded en la cual la dirección de la celda se puede pasar en notación Excel: `FindCell(ACellStr: String)` o `GetCell(ACellStr: String)`. Por favor, estar al tanto de que estas funciones retornan un `puntero` al dato de la celda (tipo `PCell`). ¡ No olvidarse de dereferenciar los punteros !. La diferencia entre `FindCell` y `GetCell` es que la modalidad uno retorna `nil`, si la celda no existe todavía, mientras que la última crea en este caso una celda vacía.
130130
131131``` pascal
132132if MyWorksheet.FindCell('A1') = nil then
133133 WriteLn('Cell A1 does not exist.');
134134```
135135
136136This is the declaration of the cell's data type:
137137
138138``` pascal
139139type
140140 TCell = record
141141 { Location of the cell }
142142 Worksheet: TsWorksheet;
143143 Col: Cardinal; // zero-based
144144 Row: Cardinal; // zero-based
145145
146146 { Index of format record }
147147 FormatIndex: Integer;
148148
149149 { Status flags }
150150 Flags: TsCellFlags; // (cfHasComment, cfMerged, cfHyperlink, ...)
151151
152152 { Cell content }
153153 UTF8StringValue: String; // strings cannot be part of a variant record
154154 FormulaValue: String;
155155 case ContentType: TCellContentType of // must be at the end of the declaration
156156 cctEmpty : (); // has no data at all
157157 cctFormula : (); // UTF8StringValue is outside the variant record
158158 cctNumber : (Numbervalue: Double);
159159 cctUTF8String : (); // FormulaValue is outside the variant record
160160 cctDateTime : (DateTimevalue: TDateTime);
161161 cctBool : (BoolValue: boolean);
162162 cctError : (ErrorValue: TsErrorValue);
163163 end;
164164 PCell = ^TCell;
165165```
166166
167167The field `ContentType` indicates which data type is stored in the cell:
168168
169169``` pascal
170170type
171171 TCellContentType = (cctEmpty, cctFormula, cctNumber, cctUTF8String, cctDateTime, cctBool, cctError);
172172```
173173
174174According to this field the corresponding data can be found in the fields
175175
176176- `FormulaValue` (for `ContentType=cctFormula`),
177177- `NumberValue` (for `ContentType=cctNumber`), or
178178- `UTF8StringValue` (for `ContentType=cctUTF8String`), or
179179- `DateTimeValue` (for `ContentType=cctDateTime`), or
180180- `BoolValue` (for `ContentType=cctBool`), i.e. `TRUE` or `FALSE`, or
181181- `ErrorValue` (for `ContentType=cctError`).
182182
183183Due to usage of a variant record most of these values are overlapping, i.e. modification of `NumberValue` affects also the other values. Therefore, always respect the `ContentType` when accessing the `TCell` record directly (the worksheet methods discussed below consider this automatically).
184184
185185> **Note:** After calculation of a formula or after reading of a file, the `ContentType` of the formula cell is converted to that of the result. Then the presence of a formula can only be detetected from the `FormulaValue` string (or call `HasFormula(cell)` of unit *fpsUtils*).
186186
187187Adding values to a cell is most easily accompished by using one of the `WriteXXXX` methods of the worksheet. The most important ones are:
188188
189189``` pascal
190190type
191191 TsWorksheet = class
192192 ...
193193 { Writing of currency values }
194194 function WriteCurrency(ARow, ACol: Cardinal; AValue: Double;
195195 ANumFormat: TsNumberFormat = nfCurrency; ADecimals: Integer = 2;
196196 ACurrencySymbol: String = '?'; APosCurrFormat: Integer = -1;
197197 ANegCurrFormat: Integer = -1): PCell; overload;
198198 procedure WriteCurrency(ACell: PCell; AValue: Double;
199199 ANumFormat: TsNumberFormat = nfCurrency; ADecimals: Integer = -1;
200200 ACurrencySymbol: String = '?'; APosCurrFormat: Integer = -1;
201201 ANegCurrFormat: Integer = -1); overload;
202202 function WriteCurrency(ARow, ACol: Cardinal; AValue: Double;
203203 ANumFormat: TsNumberFormat; ANumFormatString: String): PCell; overload;
204204 procedure WriteCurrency(ACell: PCell; AValue: Double;
205205 ANumFormat: TsNumberFormat; ANumFormatString: String); overload;
206206
207207 { Writing of date/time values }
208208 function WriteDateTime(ARow, ACol: Cardinal; AValue: TDateTime): PCell; overload;
209209 procedure WriteDateTime(ACell: PCell; AValue: TDateTime); overload;
210210 function WriteDateTime(ARow, ACol: Cardinal; AValue: TDateTime;
211211 ANumFormat: TsNumberFormat; ANumFormatStr: String = ''): PCell; overload;
212212 procedure WriteDateTime(ACell: PCell; AValue: TDateTime;
213213 ANumFormat: TsNumberFormat; ANumFormatStr: String = ''); overload;
214214 function WriteDateTime(ARow, ACol: Cardinal; AValue: TDateTime;
215215 ANumFormatStr: String): PCell; overload;
216216 procedure WriteDateTime(ACell: PCell; AValue: TDateTime;
217217 ANumFormatStr: String); overload;
218218
219219 { Writing of number values }
220220 function WriteNumber(ARow, ACol: Cardinal; ANumber: double): PCell; overload;
221221 procedure WriteNumber(ACell: PCell; ANumber: Double); overload;
222222 function WriteNumber(ARow, ACol: Cardinal; ANumber: double;
223223 ANumFormat: TsNumberFormat; ADecimals: Byte = 2): PCell; overload;
224224 procedure WriteNumber(ACell: PCell; ANumber: Double;
225225 ANumFormat: TsNumberFormat; ADecimals: Byte = 2); overload;
226226 function WriteNumber(ARow, ACol: Cardinal; ANumber: double;
227227 ANumFormat: TsNumberFormat; ANumFormatString: String): PCell; overload;
228228 procedure WriteNumber(ACell: PCell; ANumber: Double;
229229 ANumFormat: TsNumberFormat; ANumFormatString: String); overload;
230230
231231 { Writing of string values }
232232 function WriteText(ARow, ACol: Cardinal; AText: ansistring;
233233 ARichTextParams: TsRichTextParams = nil): PCell; overload;
234234 procedure WriteText(ACell: PCell; AText: String;
235235 ARichTextparams: TsRichTextParams = nil); overload;
236236
237237 // the old string methods "WriteUTF8Text" are deprecated now
238238 ...
239239```
240240
241241Some of these methods exist in overloaded versions in which cell formatting parameters can be added together with the cell value. Correspondingly to writing, there is also a number of `worksheet` methods for reading the cell values:
242242
243243``` pascal
244244type
245245 TsWorksheet = class
246246 ...
247247 { Reading cell content as a string }
248248 function ReadAsText(ARow, ACol: Cardinal): string; overload;
249249 function ReadAsText(ACell: PCell): string; overload;
250250 function ReadAsText(ACell: PCell; AFormatSettings: TFormatSettings): string; overload;
251251
252252 { Reading cell content as a number }
253253 function ReadAsNumber(ARow, ACol: Cardinal): Double; overload;
254254 function ReadAsNumber(ACell: PCell): Double; overload;
255255 function ReadNumericValue(ACell: PCell; out AValue: Double): Boolean;
256256
257257 { Reading cell content as a date/time value }
258258 function ReadAsDateTime(ARow, ACol: Cardinal; out AResult: TDateTime): Boolean; overload;
259259 function ReadAsDateTime(ACell: PCell; out AResult: TDateTime): Boolean; overload;
260260 ...
261261```
262262
263263`FormatIndex` is the index of the cell format record. It describes the formatting attributes of a cell. These records are collected by an internal list of the workbook and are defined like this:
264264
265265``` pascal
266266type
267267 TsCellFormat = record
268268 FontIndex: Integer;
269269 TextRotation: TsTextRotation;
270270 HorAlignment: TsHorAlignment;
271271 VertAlignment: TsVertAlignment;
272272 Border: TsCellBorders;
273273 BorderStyles: TsCellBorderStyles;
274274 Background: TsFillPattern;
275275 NumberFormat: TsNumberFormat;
276276 NumberFormatStr: String;
277277 UsedFormattingFields: TsUsedFormattingFields;
278278 //uffTextRotation, uffFont, uffBold, uffBorder, uffBackground, uffNumberFormat, uffWordWrap, uffHorAlign, uffVertAlign
279279 end;
280280```
281281
282282- `FontIndex`: text font by specifying the index in the workbook's font list
283283- `TextRotation`: specifies whether the cell text is written horizontally or vertically
284284- `HorAlignment`: left-aligned, horizontally centered, or right-aligned text
285285- `VertAlignment`: top, bottom or vertically centered text
286286- `Border`: a set of flags indicating that - if set - a border line is drawn at the left, top, right, or bottom cell edge. The lines are drawn according to the `BorderStyles` which define the linestyle and color of the border.
287287- `Background`: a record defining the background fill of a cell (pattern style, pattern color, and background color - see chapter on cell background below).
288288- `NumberFormat` and `NumberFormatStr` specify how number or date/time values are formatted (e.g., number of decimal places, long or short date format, etc.).
289289- Only those format attributes for which a flag is set in the `UsedFormattingFields` are considered when formatting a cell. If a flag is not included then the corresponding attribute is ignored and replaced by its default value.
290290
291291For specifying a format for a given cell call the corresponding the worksheet method `WriteXXXX`, for retrieving a format call `ReadXXXX`. These methods usually get a pointer to the cell as a parameter, but there are also overloaded versions which accept the row and column index. Moreover, formatting styles can also be applied directly to the cell by using a record helper implemented in unit *fpsCell*.
292292
293293See cell formatting below for a more detailed description.
294294
295295#### Columns and rows
296296
297297Column and row records are added for each column and row having a non-default size:
298298
299299``` pascal
300300type
301301 TCol = record
302302 Col: Cardinal;
303303 Width: Single;
304304 end;
305305 PCol = ^TCol;
306306
307307 TRow = record
308308 Row: Cardinal;
309309 Height: Single;
310310 end;
311311 PRow = ^TRow;
312312```
313313
314314**Column widths** and **row heights** can be specified in a variety of units defined by the type `TsSizeUnits = (suChars, suLines, suMillimeters, suCentimeters, suPoints, suInches)`. `suChars` refers to the count of `0` characters fitting into the column width - this is the way how Excel defines column widths. `suLines` is the number of lines fitting into the row height. Both units are based on the character size of the workbook's default font. The other units are conventional physical length units (1 cm = 10 mm, 1 inch = 25.4 mm = 72 pt). Fractional values are accepted. The workbook and worksheets store lengths internally in millimeters (`MyWorkbook.Units`).
315315
316316The Office applications usually adjust the row heights automatically according to the font or text rotation of the cell content, and empty rows have a predefined default row height. In order to overrun this and to set a predefined row height use the worksheet method `WriteRowHeight`. In the same way the width of columns can be set to a specific value by calling `WriteColWidth`. The height/width of a particular row/column can be retrieved by means of the methods `GetRowHeight` or `GetColHeight`. Note that these methods return the default row heights/column widths if there are no `TRow`/`TCol` records.
317317
318318``` pascal
319319type TsWorksheet = class
320320 ...
321321 { Set row height }
322322 procedure WriteRowHeight(ARowIndex: Cardinal; AHeight: Single; AUnits: TsSizeUnits);
323323 { Set column width }
324324 procedure WriteColWidth(AColIndex: Cardinal; AWidth: Single; AUnits: TsSizeUnits);
325325 { Set default row height }
326326 procedure WriteDefaultRowHeight(AHeight: Single; AUnits: TsSizeUnits);
327327 {Set default cokumn width }
328328 procedure WriteDefaultColWidth(AWidth: Single; AUnits: TsSizeUnits);
329329
330330 { Return row height }
331331 function GetRowHeight(ARowIndex: Cardinal; AUnits: TsSizeUnits): Single;
332332 { Return column width }
333333 function GetColWidth(AColIndex: Cardinal; AUnits: TsSizeUnits): Single;
334334 { Return default row height }
335335 function ReadDefaultRowHeight(AUnits: TsSizeUnits): Single;
336336 { Return default column width }
337337 function ReadDefaultColWidth(AUnits: TsSizeUnits): Single;
338338
339339 property DefaultRowHeight: Single;
340340 property DefaultColWidht: Single;
341341```
342342
343343There are also overloaded versions of these methods which do not require the `AUnits` parameter. In this case, row heights are defined in terms of line count, and column widthts are defined in terms of character count. Note that these variants are from previos versions and are deprecated now.
344344
345345The **default row height** and **default column width** is used unless a specific value is assigned to individual rows or columns. The property `DefaultRowHeight` expects the value to be in line count, and `DefaultColWidth` expects it to be in "0" character count. Other size units can be applied if using the corresponding WriteXXXX and ReadXXXX methods.
346346
347347### Formulas
348348
349349Two kinds of formulas are supported by FPSpreadsheet:
350350
351351- **String formulas**: These are written in strings just like in the office applications, for example `"=ROUND(A1+B1,0)"`. They are used internally in the files of Open/LibreOffice and Excel *.xlsx*.
352352- **RPN formulas** are used internally by the binary *.xls* Excel files. They are written in Reverse Polish Notation (RPN), for example: `A1, B1, Add, 0, ROUND`.
353353
354354The current trunk version of FPSpreadsheet can convert between string and rpn formulas. Formulas in both types can be calculated. The cell record stores the string formula in the field `FormulaValue`. If a spreadsheet containing formulas is to be saved in a binary Excel format, the RPN formulas required are generated automatically.
355355
356356FPSpreadsheet supports the majority of the formulas provided by the common spreadsheet applications. However, when reading a file created by these applications, there is always a chance that an unsupported formula is contained. To avoid crashing of fpspreadsheet, reading of formulas is disabled by default; the cell displays only the result of the formula written by the Office application. To activate reading of formulas add the element `boReadformulas` to the workbook's `Options` before opening the file.
357357
358358Calculation of formulas is normally not needed when a file is written by FPSpreadsheet for opening in an Office application because that automatically calculates the formula results. If the same file, however, is openend by an application based on FPSpreadsheet the calculated cells would be empty because the formulas are not automatically calculated by default. To activate calculation of formulas before writing a spreadsheet to file you have to add the option `boCalcBeforeSaving` to the workbook's `Options`.
359359
360360If FPSpreadshet is used in an interactive application (such as the *spready* demo found in the *examples* folder of the FPSpreadsheet installation) it is desirable to calculate formulas automatically whenever formula strings or cell values are changed by the user. This can be achieved by the option `boAutoCalc` in the workbook's `Options`.
361361
362362The most general setting regarding formulas, therefore, is
363363
364364``` pascal
365365 MyWorkbook.Options := MyWorkbook.Options + [boReadFormulas, boCalcBeforeSaving, boAutoCalc];
366366```
367367
368368#### String formulas
369369
370370String formulas are written in the same way as in the Office applications. The worksheet method for creating a string formula is `WriteFormula`:
371371
372372``` pascal
373373var
374374 MyWorksheet: TsWorksheet;
375375//...
376376 MyWorksheet.WriteFormula(0, 1, '=ROUND(A1+B2+1.215,0)');
377377 // By default, use dot as decimal and comma as list separator!
378378```
379379
380380A few notes on **syntax**:
381381
382382- The leading `=` character which identifies formulas in the Office applications is not absolutely necessary here and can be dropped. The formula is stored in the cell record without it.
383383- The case of the formula name is ignored.
384384- Spaces can be added for better readability, but they will be lost when saving.
385385- Strings must be enclosed in double quotes.
386386- Normally, floating point numbers must be entered with a dot as decimal separator, and a comma must be used to separate function arguments.
387387- Setting the optional parameter `ALocalized` of the worksheet methods `WriteFormula` to `TRUE`, however, allows to use localized decimal and list separators taken from the workbook's `FormatSettings` - see *spready* demo.
388388
389389``` pascal
390390var
391391 MyWorksheet: TsWorksheet;
392392//...
393393 MyWorksheet.WriteFormula(0, 1, '=ROUND(A1+B2+1,215;0)', true);
394394 // Because of the "true" the formula parser accepts the comma as decimal and the
395395 // semicolon as list separator if the workbook's FormatSettings are set up like this.
396396```
397397
398398#### RPN formulas
399399
400400At application level, string formulas are mainly used, and RPN formulas are of little practical importance. Therefore, documentation of RPN formulas has been removed from this main FPSpreadsheet wiki and can be found in the article [[RPN Formulas in FPSpreadsheet|"RPN Formulas in FPSpreadsheet"]].
401401
402402#### Shared formulas and array formulas
403403
404404- **Shared formulas** are only supported for reading (from Excel files).
405405- **Array formulas** are not supported, currently.
406406
407407#### List of built-in formulas
408408
409409FPSpreadsheet supports more than 80 built-in formulas. In order not to blow up this wiki page too much documentation of these formulas has been moved to the [[FPSpreadsheet: List of formulas|separate document "List of formulas"]].
410410
411411To learn more about the functions available, look at file *testcases_calcrpnformula.inc* in the *tests* folder of the FPSpreadsheet installation where every function is included with at least one sample.
412412
413413#### Extending FPSpreadsheet by user-defined formulas
414414
415415Although the built-in formulas cover most of the applications there may be a need to access a formula which is available in the Office application, but not in FPSpreadsheet. For this reason, the library supports a registration mechanism which allows to add user-defined functions to the spreadsheets. This can be done by calling the procedure `RegisterFunction` from the unit *fpsExprParser*:
416416
417417``` pascal
418418procedure RegisterFunction(const AName: ShortString; const AResultType: Char;
419419 const AParamTypes: String; const AExcelCode: Integer; ACallBack: TsExprFunctionCallBack); overload;
420420
421421procedure RegisterFunction(const AName: ShortString; const AResultType: Char;
422422 const AParamTypes: String; const AExcelCode: Integer; ACallBack: TsExprEventCallBack); overload;
423423```
424424
425425- `AName` specifies the name under which the function will be called in the spreadsheet. It must match the name of the formula in the Office application.
426426- `AResultType` is a character which identifies the data type of the function result:
427427 - `'F'` - floating point number
428428 - `'I'` - integer
429429 - `'D'` - date/time
430430 - `'B'` - boolean
431431 - `'S'` - string
432432- `AParamTypes` is a string in which each character identifies the data type of the corresponding argument. In addition to the list shown above the following symbols can be used:
433433 - `'?'` - any type
434434 - `'+'` - must be the last character. It means that the preceding character is repeated indefinitely. This allows for an arbitrary argument count. Please note, however, that Excel supports only up to 30 arguments.
435435 - lowercase `'f', 'i', 'd', 'b', 's'` indicate optional parameters of the type explained above. Of course, uppercase symbols cannot follow lower-case symbols.
436436- `AExcelCode` is the identifier of the function in xls files. See "OpenOffice Documentation of the Microsoft Excel File Format", section 3.11, for a list.
437437- `ACallback` identifies which function is called by FPSpreadsheet for calculation of the formula. It can either be a procedure or an event handler.
438438
439439``` pascal
440440type
441441 TsExprFunctionCallBack = procedure (var Result: TsExpressionResult; const Args: TsExprParameterArray);
442442 TsExprFunctionEvent = procedure (var Result: TsExpressionResult; const Args: TsExprParameterArray) of object;
443443```
444444
445445The `TsExpressionResult` is a variant record containing result or argument data of several types:
446446
447447``` pascal
448448type
449449 TsResultType = (rtEmpty, rtBoolean, rtInteger, rtFloat, rtDateTime, rtString,
450450 rtCell, rtCellRange, rtError, rtAny);
451451
452452 TsExpressionResult = record
453453 Worksheet : TsWorksheet;
454454 ResString : String;
455455 case ResultType : TsResultType of
456456 rtEmpty : ();
457457 rtError : (ResError : TsErrorValue);
458458 rtBoolean : (ResBoolean : Boolean);
459459 rtInteger : (ResInteger : Int64);
460460 rtFloat : (ResFloat : TsExprFloat);
461461 rtDateTime : (ResDateTime : TDatetime);
462462 rtCell : (ResRow, ResCol : Cardinal);
463463 rtCellRange : (ResCellRange : TsCellRange);
464464 rtString : ();
465465 end;
466466
467467 TsExprParameterArray = array of TsExpressionResult;
468468```
469469
470470As an example we show here the code for the `CONCATENATE()` formula which joins two or more strings:
471471
472472``` pascal
473473const
474474 INT_EXCEL_SHEET_FUNC_CONCATENATE = 336;
475475...
476476 RegisterFunction('CONCATENATE', 'S', 'S+', INT_EXCEL_SHEET_FUNC_CONCATENATE, @fpsCONCATENATE);
477477
478478procedure fpsCONCATENATE(var Result: TsExpressionResult; const Args: TsExprParameterArray);
479479// CONCATENATE( text1, text2, ... text_n )
480480var
481481 s: String;
482482 i: Integer;
483483begin
484484 s := '';
485485 for i:=0 to Length(Args)-1 do
486486 begin
487487 if Args[i].ResultType = rtError then
488488 begin
489489 Result := ErrorResult(Args[i].ResError);
490490 exit;
491491 end;
492492 s := s + ArgToString(Args[i]);
493493 // "ArgToString" simplifies getting the string from a TsExpressionResult as
494494 // a string may be contained in the ResString and in the ResCell fields.
495495 // There is such a function for each basic data type.
496496 end;
497497 Result := StringResult(s);
498498 // "StringResult" stores the string s in the ResString field of the
499499 // TsExpressionResult and sets the ResultType to rtString.
500500 // There is such a function for each basic data type.
501501end;
502502```
503503
504504There is a worked-out example (*demo_formula_func.pas*) in the folder *examples/other* of the FPSpreadsheet installation. In this demo, four financial functions (`FV()`, `PV()`, `PMT()`, `RATE()`) are added to FPSpreadsheet.
505505
506506### Cell formatting
507507
508508#### Number and date/time formats
509509
510510Numbers and date/time values can be displayed in a variety of formats. In FPSpreadsheet this can be achieved in two ways:
511511
512512- using **built-in number formats** by specifiying a value for the `NumberFormat` of the cell
513513- using a custom **format string**.
514514
515515Number formats can be specified by these worksheet methods:
516516
517517``` pascal
518518type
519519 TsWorksheet = class
520520 public
521521 // Set number formats alone
522522 function WriteNumberFormat(ARow, ACol: Cardinal; ANumberFormat: TsNumberFormat;
523523 const AFormatString: String = ''): PCell; overload;
524524 procedure WriteNumberFormat(ACell: PCell; ANumberFormat: TsNumberFormat;
525525 const AFormatString: String = ''); overload;
526526
527527 function WriteNumberFormat(ARow, ACol: Cardinal; ANumFormat: TsNumberFormat;
528528 ADecimals: Integer; ACurrencySymbol: String = ''; APosCurrFormat: Integer = -1;
529529 ANegCurrFormat: Integer = -1): PCell; overload;
530530 procedure WriteNumberFormat(ACell: PCell; ANumFormat: TsNumberFormat;
531531 ADecimals: Integer; ACurrencySymbol: String = '';
532532 APosCurrFormat: Integer = -1; ANegCurrFormat: Integer = -1); overload;
533533
534534 function WriteFractionFormat(ARow, ACol: Cardinal; AMixedFraction: Boolean;
535535 ANumeratorDigits, ADenominatorDigits: Integer): PCell; overload;
536536 procedure WriteFractionFormat(ACell: PCell; AMixedFraction: Boolean;
537537 ANumeratorDigits, ADenominatorDigits: Integer); overload;
538538
539539 // Set date/time formats alone
540540 function WriteDateTimeFormat(ARow, ACol: Cardinal; ANumberFormat: TsNumberFormat;
541541 const AFormatString: String = ''): PCell; overload;
542542 procedure WriteDateTimeFormat(ACell: PCell; ANumberFormat: TsNumberFormat;
543543 const AFormatString: String = ''); overload;
544544
545545 // Set cell values and number formats in one call
546546
547547 // number values
548548 function WriteNumber(ARow, ACol: Cardinal; ANumber: double;
549549 AFormat: TsNumberFormat = nfGeneral; ADecimals: Byte = 2;
550550 ACurrencySymbol: String = ''): PCell; overload;
551551 procedure WriteNumber(ACell: PCell; ANumber: Double; AFormat: TsNumberFormat = nfGeneral;
552552 ADecimals: Byte = 2; ACurrencySymbol: String = ''); overload;
553553 function WriteNumber(ARow, ACol: Cardinal; ANumber: double;
554554 AFormat: TsNumberFormat; AFormatString: String): PCell; overload;
555555 procedure WriteNumber(ACell: PCell; ANumber: Double;
556556 AFormat: TsNumberFormat; AFormatString: String); overload;
557557
558558 // date/time values
559559 function WriteDateTime(ARow, ACol: Cardinal; AValue: TDateTime;
560560 AFormat: TsNumberFormat = nfShortDateTime; AFormatStr: String = ''): PCell; overload;
561561 procedure WriteDateTime(ACell: PCell; AValue: TDateTime;
562562 AFormat: TsNumberFormat = nfShortDateTime; AFormatStr: String = ''); overload;
563563 function WriteDateTime(ARow, ACol: Cardinal; AValue: TDateTime;
564564 AFormatStr: String): PCell; overload;
565565 procedure WriteDateTime(ACell: PCell; AValue: TDateTime;
566566 AFormatStr: String); overload;
567567
568568 // currency values
569569 function WriteCurrency(ARow, ACol: Cardinal; AValue: Double;
570570 AFormat: TsNumberFormat = nfCurrency; ADecimals: Integer = 2;
571571 ACurrencySymbol: String = '?'; APosCurrFormat: Integer = -1;
572572 ANegCurrFormat: Integer = -1): PCell; overload;
573573 procedure WriteCurrency(ACell: PCell; AValue: Double;
574574 AFormat: TsNumberFormat = nfCurrency; ADecimals: Integer = -1;
575575 ACurrencySymbol: String = '?'; APosCurrFormat: Integer = -1;
576576 ANegCurrFormat: Integer = -1); overload;
577577 function WriteCurrency(ARow, ACol: Cardinal; AValue: Double;
578578 AFormat: TsNumberFormat; AFormatString: String): PCell; overload;
579579 procedure WriteCurrency(ACell: PCell; AValue: Double;
580580 AFormat: TsNumberFormat; AFormatString: String); overload;
581581 ...
582582```
583583
584584##### Built-in number formats
585585
586586Los **formatos internos** están definidos por la enumeración `TsNumberFormat`. A pesar de su nombre, los elementos cubren tanto valores de número como la fecha/hora:
587587
588588``` pascal
589589type
590590 TsNumberFormat = (
591591 // De propósito general para todos los números.
592592 nfGeneral,
593593 // numbers
594594 nfFixed, nfFixedTh, nfExp, nfPercentage, nfFraction,
595595 // currency
596596 nfCurrency, nfCurrencyRed,
597597 // dates and times
598598 nfShortDateTime, nfShortDate, nfLongDate, nfShortTime, nfLongTime,
599599 nfShortTimeAM, nfLongTimeAM, nfDayMonth, nfMonthYear, nfTimeInterval,
600600 // other (using format string)
601601 nfCustom);
602602```
603603
604604- **nfGeneral** corresponde al formato por defecto mostrando tantos decimales como es posible (el número `3.141592654` would be unchanged.)
605605- **nfFixed** limita los decimales. El número de posiciones decimales se tiene que especificar en la llamada a `WriteNumber`. Example: with 2 decimals, the number `3.141592654` becomes `3.14`.
606606- **nfFixedTh**: similar a `nfFixed`, pero añade un separador de miles cuando el número se muestra como una cadena: 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.
607607- **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).
608608- **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).
609609- **nfFraction** presents a number as a fraction. Details (mixed fraction?, maximum digit count for numerator or denominator) for can be specified in the worksheet method `WriteFractionFormat`.
610610- **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.
611611- **nfCurrendyRed** like `nfCurrency`, in addition negative values are displayed in red.
612612- **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.
613613- **nfShortDate** creates a date string showing day + two-digit month + two-digit year
614614- **nfShortTime** creates a time string showing hours + minutes.
615615- **nfLongTime**, similar, but includes seconds as well
616616- **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.
617617- **nfLongTimeAM**, like `nfShortTimeAM`, but includes seconds
618618- **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.
619619- **nfCustom** allows to specify a dedicated formatting string.
620620
621621As 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.
622622
623623##### Number format strings
624624
625625In 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 Excel syntax which is close to the syntax of fpc's `FormatFloat` and `FormatDateTime` commands (accepted as well, see the online-help for these functions).
626626
627627Here is a basic list of the symbols used:
628628
629-<thead>
630-
631-</thead>
632-<tbody>
633-
634-1.2345678 --&gt; <code>'1.2345678'</code></td>
635-
636-<code>'0.0'</code>: 1 --&gt; <code>'1.0'</code><br />
637-<code>'0.0'</code>: 1.2345678 --&gt; <code>'1.2'</code></td>
638-
639-<code>'0.*'</code>: 1.2345678 --&gt; <code>'1.2'</code></td>
640-
641-<code>'0.0??'</code>: 1 --&gt; <code>'1.0 '</code></td>
642-
643-<code>'0.00,'</code>: 1200 --&gt; <code>'1.20'</code></td>
644-
645-<code>'# #/#'</code>: 1.5 --&gt; <code>'1 1/2'</code><br />
646-<code>'# #/16'</code>: 1.5 --&gt; <code>'1 8/16'</code><br />
647-also: see date/time examples below</td>
648-
649-Jan 3, 2012 --&gt; <code>'2012-01-03'</code><br />
650-In this example, the <code>DateSeparator</code> is a dash character (<code>-</code>).</td>
651-
652-Jan 3, 2012 --&gt; <code>'12-01-03'</code></td>
653-
654-Please note that the <code>m</code> code can also be interpreted as the "minutes" of a time value (see below).</td>
655-
656-Jan 3, 2012 --&gt; <code>'2012-1-03'</code></td>
657-
658-Please note that the <code>mm</code> code can also be interpreted as the "minutes" of a time value (see below).</td>
659-
660-Jan 3, 2012 --&gt; <code>'2012-01-03'</code></td>
661-
662-Jan 3, 2012 --&gt; <code>'2012-Jan-03'</code></td>
663-
664-Jan 3, 2012 --&gt; <code>'2012-January-03'</code></td>
665-
666-Jan 3, 2012 --&gt; <code>'2012-01-3'</code></td>
667-
668-Jan 3, 2012 --&gt; <code>'2012-01-03'</code></td>
669-
670-Jan 03, 2012 --&gt; <code>'Tue 2012-01-03'</code></td>
671-
672-Jan 03, 2012 --&gt; <code>'Tuesday 2012-01-03'</code></td>
673-
674-0.25 --&gt; <code>'6:00'</code></td>
675-
676-0.25 --&gt; <code>'06:00'</code></td>
677-
678-1.25 --&gt; <code>'30:00'</code></td>
679-
680-0.25 --&gt; <code>'6:0'</code></td>
681-
682-0.25 --&gt; <code>'6:00'</code></td>
683-
684-1.25 --&gt; <code>'1800:00'</code></td>
685-
686-0.25 --&gt; <code>'06:00:0'</code></td>
687-
688-0.25 --&gt; <code>'06:00:00'</code></td>
689-
690-1.25 --&gt; <code>'108000'</code></td>
691-
692-0.25 --&gt; <code>'6:00:00 AM'</code></td>
693-
694-Jan 3, 2012 --&gt; <code>'2012/01/03'</code> (i.e. the <code>/</code> is not replaced by the <code>DateSeparator</code> of the workbook).</td>
695-
696-Jan 3, 2012 --&gt; <code>'2012/01/03'</code></td>
697-
698-1200 --&gt; <code>'1,200$'</code><br />
699--1200 --&gt; <code>'1,200$'</code><br />
700-0 --&gt; <code>'-'</code></td>
701-
702--1200 --&gt; <code>'(1200)$'</code></td>
703-
704--1200 --&gt; '<code>($ 1200.00)</code>'</td>
705-
706-</tbody>
629+| Symbol | Meaning | Format string: Number --> Output string |
630+|---|---|---|
631+| `General` | Displays all decimal places of the number | `'General'`: · 1.2345678 --> `'1.2345678'` |
632+| `0` | Displays insignificant zeros if a number has less digits than there are zeros in the format. If used for decimal places then the number is rounded to as many decimal places as 0s are found. | `'000'`: 1 --> `'001'` · `'0.0'`: 1 --> `'1.0'` · `'0.0'`: 1.2345678 --> `'1.2'` |
633+| `*` | Like "0" above, but does not display insignificant zeros. | `'0.*'`: 1 --> `'1.'` · `'0.*'`: 1.2345678 --> `'1.2'` |
634+| `?` | Like "0" above, but insignificant zeros are replaced by space characters. Good for aligning decimal points and fractions | `'??0'`: 1 --> `' 1'` · `'0.0??'`: 1 --> `'1.0 '` |
635+| `.` | Decimal separator; will be replaced by the value used in the `DecimalSeparator` of the workbook's `FormatSettings` | `'0.00'`: 8.9 --> `'8.90'` |
636+| `,` | Thousand separator; will be replaced by the value used in the `ThousandSeparator` of the workbook's `FormatSettings`. If at the end of a number formatting sequence the displayed value is divided by 1000. | `'#,##0.00'`: 1200 --> `'1,200.00'` · `'0.00,'`: 1200 --> `'1.20'` |
637+| `E+`, `e+` | Displays a number in exponential format. The digits used for the exponent are defined by the number of zeros added the this symbol. The sign of the exponent is shown for positive and negative exponents. | `'0.00E+00'`: 1200 --> `1.20E+03` |
638+| `E-`, `e-` | Displays a number in exponential format. The digits used for the exponent are defined by the number of zeros added the this symbol. The sign of the exponent is shown only for negative exponents. | `'0.00e-000'`: 1200 --> `1.20e003` |
639+| `%` | Displays the number as a "percentage", i.e. the number is multiplied by 100 and a `%` sign is added. | `'0.0%'`: 0.75 --> `75.0%` |
640+| `/` | This symbol has two meanings: if the cell represents a "number" then the slash indicates formatting as fraction, place holders for numerator and denominator must follow. If the cell represents a "date/time" then the slash indicates the date separator which will be replaced by the `DateSeparator` of the workbook's `FormatSettings` | `'#/#'`: 1.5 --> `'3/2'` · `'# #/#'`: 1.5 --> `'1 1/2'` · `'# #/16'`: 1.5 --> `'1 8/16'` · also: see date/time examples below |
641+| `:` | Separator between hours, minutes and seconds of a date/time value. Will be replaced by the `TimeSeparator` of the workbook's `FormatSettings`. | see examples below |
642+| `yyyy` | Place holder for the year of a date/time value. The year is displayed as a four-digit number. | `'yyyy/mm/dd'`: · Jan 3, 2012 --> `'2012-01-03'` · In this example, the `DateSeparator` is a dash character (`-`). |
643+| `yy` | Place holder for the year of a date/time value. The year is displayed as a two-digit number. | `'yy/mm/dd'`: · Jan 3, 2012 --> `'12-01-03'` |
644+| `m` | Place holder for the month of a date/time value. The month is shown as a number without extra digits. · Please note that the `m` code can also be interpreted as the "minutes" of a time value (see below). | `'yyyy/m/dd'`: · Jan 3, 2012 --> `'2012-1-03'` |
645+| `mm` | Place holder for the month of a date/time value. The month is shown as a two-digit number, i.e. a leading zero is added for January to September. · Please note that the `mm` code can also be interpreted as the "minutes" of a time value (see below). | `'yyyy/mm/dd'`: · Jan 3, 2012 --> `'2012-01-03'` |
646+| `mmm` | Place holder for the month of a date/time value. The month is displayed by its abbreviated name. | `'yyyy/mmm/dd'`: · Jan 3, 2012 --> `'2012-Jan-03'` |
647+| `mmmm` | Place holder for the month of a date/time value. The month is displayed by its full name. | `'yyyy/mmm/dd'`: · Jan 3, 2012 --> `'2012-January-03'` |
648+| `d` | Place holder for the day of a date/time value to be displayed as a number. The day is displayed as a simple number, without adding a leading zero. | `'yyyy/mm/d'`: · Jan 3, 2012 --> `'2012-01-3'` |
649+| `dd` | Place holder for the day of a date/time value to be displayed as a number. `dd` adds a leading zero to single-digit day numbers. | `'yyyy/mm/dd'`: · Jan 3, 2012 --> `'2012-01-03'` |
650+| `ddd` | Place holder for the day of a date/time value. The day is displayed as its abbreviated name. | `'dddd, yyyy/mm/ddd'`: · Jan 03, 2012 --> `'Tue 2012-01-03'` |
651+| `dddd` | Place holder for the day of a date/time value. The day is displayed as its full name. | `'dddd, yyyy/mmmm/dd'`: · Jan 03, 2012 --> `'Tuesday 2012-01-03'` |
652+| `h` | Place holder of the hour part of a date/time value. The hour is displayed as a simple number, without adding a leading zero. | `'h:mm'`: · 0.25 --> `'6:00'` |
653+| `hh` | Place holder of the hour part of a date/time value. The hour is displayed with a leading zero if the hour is less than 10. | `'hh:mm'`: · 0.25 --> `'06:00'` |
654+| `[hh]`, or `[h]` | Displays elapsed time such that the hour part can become greater than 23 | `'[h]:mm'`: · 1.25 --> `'30:00'` |
655+| `m` | Place holder of the minutes part of a date/time value. The minutes are shown as a simple number without adding a leading zero. Note that if the `m` codes are surrounded by date symbols (`y`, `d`) then they are interpreted as "month". | `'h:m'`: · 0.25 --> `'6:0'` |
656+| `mm` | Place holder of the minutes part of a date/time value. Single-digit minutes are displayed with a leading zero. Note that if the `mm` code is surrounded by date symbols (`y`, `d`) then it is interpreted as "month". | `'h:mm'`: · 0.25 --> `'6:00'` |
657+| `[mm]`, or `[m]` | Displays elapsed time such that the minute part can become greater than 59 | `'[mm]:ss'`: · 1.25 --> `'1800:00'` |
658+| `s` | Place holder of the seconds part of a date/time value. The seconds are displayed as a simple number, without adding a leading zero. | `'hh:mm:s'`: · 0.25 --> `'06:00:0'` |
659+| `ss` | Place holder of the seconds part of a date/time value. Single-digit seconds are displayed with a leading zero. | `'hh:mm:ss'`: · 0.25 --> `'06:00:00'` |
660+| `[ss]`, or `[s]` | Displays elapsed time such that the seconds part can become greater than 59 | `'[ss]'`: · 1.25 --> `'108000'` |
661+| `AM/PM`, `am/pm`, `A/P`, or `a/p` | Displays the time in the 12-hour format. | `'hh:mm:ss AM/PM'`: · 0.25 --> `'6:00:00 AM'` |
662+| `"` | The text enclosed by quotation marks is inserted into the formatted strings literally. | `'yyyy"/"mm"/"dd'`: · Jan 3, 2012 --> `'2012/01/03'` (i.e. the `/` is not replaced by the `DateSeparator` of the workbook). |
663+| `\` | The next character of the format string appears in the result string literally. The `\` itself does not show up. | `'yyyy\/mm\/dd'`: · Jan 3, 2012 --> `'2012/01/03'` |
664+| `;` | A format string can contain up to three sections separated by the semicolon. The first section is used for positive numbers, the second section for negative numbers, and the third section for zero numbers. If the third section is missing then a zero value is formatted as specified in the first section. If the second section is missing as well then all values are formatted according to the first section. | `'"#,##0"$"';-#,##0"$";"-"'`: · 1200 --> `'1,200$'` · -1200 --> `'1,200$'` · 0 --> `'-'` |
665+| `(`, and `)` | Sometimes used for currency values to indicate negative numbers, instead of minus sign | `'#,##0"$";(#,##0)"$"'`: · -1200 --> `'(1200)$'` |
666+| `[red]` | The formatted string is displayed in the specified color. Instead of `[red]`, you can use accordingly `[black]`, `[white]`, `[green]`, `[blue]`, `[magenta]`, `[yellow]`, or `[cyan]`. Often used to highlight negative currency values. | `'"$" #,##0.00;[red]("$" #,##0.00)'`: · -1200 --> '`($ 1200.00)`' |
707667
708668#### Colores
709669
710670FPSpreadsheet soporta colores de texto, fondo de celda y bordes de celda. En la unit *fpstypes* se declaran los colores EGA básicos como constantes.
711671
712672![](/wiki-images/7/7b/DefaultPalette.png)
713673
714674``` pascal
715675type
716676 TsColor = DWORD; // ts = text style color
717677
718678const
719679 scBlack = $00000000; // Negro
720680 scWhite = $00FFFFFF; // Blanco
721681 scRed = $000000FF; // Rojo
722682 scGreen = $0000FF00; // Verde
723683 scBlue = $00FF0000; // Azul
724684 scYellow = $0000FFFF; // Amarillo
725685 scMagenta = $00FF00FF; // Magenta
726686 scCyan = $00FFFF00; // Cian
727687 scDarkRed = $00000080; // Rojo oscuro
728688 scDarkGreen = $00008000; // Verde oscuro
729689 scDarkBlue = $00800000; // Azul oscuro
730690 scOlive = $00008080; // Oliva
731691 scPurple = $00800080; // Púrpura
732692 scTeal = $00808000; // Verde azulado
733693 scSilver = $00C0C0C0; // Plateado
734694 scGray = $00808080; // Gris
735695 scGrey = scGray; // redefine to allow different spelling
736696
737697 // Identificador para color no definido
738698 scNotDefined = $40000000;
739699
740700 // Identifier for transparent color
741701 scTransparent = $20000000;
742702```
743703
744704El `TsColor` representa el **valor rgb (red,green,blue)** de un color, un solo byte utilizado para el rojo (red), otro para el verde (green), y otro para el azul(blue). El número resultante tiene notación little endian, i.e. el valor rojo va primero en memoria: `$00BBGGRR`. (Esto es directamente compatible con los valores de color tales como están definidos en la unit *graphics*).
745705
746706The high order byte is usually zero but is used internally to identify special color values, such as for undefined or transparent colors.
747707
748708> **Note:** In older versions of the library colors were defined as indexes into a color palette. **THIS IS NO LONGER WORKING.**
749709
750710Unit *fpsutils* contains some useful functions for **modification of colors**:
751711
752712- `function GetColorName(AColor: TsColor): String;`\
753713 returns the name of the colors defined above, or a string showing the rgb components for other colors.
754714- `function HighContrastColor(AColor: TsColor): TsColor;`\
755715 returns `scBlack` for a "bright", `scWhite` for a "dark" input color.
756716- `function TintedColor(AColor: TsColor; tint: Double): TsColor;`\
757717 brightens or darkens a color by applying a factor `tint = -1..+1`, where `-1` means "100% darken", `+1` means "100% brighten", and `0` means "no change". The hue of the color is preserved.
758718
759719#### Cell background
760720
761721The cell background can be filled by predefined patterns which are identified by the record `TsFillPattern`:
762722
763723``` pascal
764724type
765725 TsFillPattern = record
766726 Style: TsFillStyle; // fill style pattern as defined below
767727 FgColor: TsColor; // forground color of the fill pattern
768728 BgColor: TsColor; // background color of the fill pattern
769729 end;
770730
771731 TsFillStyle = (fsNoFill, fsSolidFill, fsGray75, fsGray50, fsGray25, fsGray12, fsGray6,
772732 fsStripeHor, fsStripeVert, fsStripeDiagUp, fsStripeDiagDown,
773733 fsThinStripeHor, fsThinStripeVert, fsThinStripeDiagUp, fsThinStripeDiagDown,
774734 fsHatchDiag, fsThinHatchDiag, fsThickHatchDiag, fsThinHatchHor);
775735```
776736
777737- Use the worksheet method `WriteBackground` to assign a fill pattern to a specific cell. Besides the cell address, this method requires the type of the fill pattern (`TsFillStyle`), and the foreground and background colors as specified by their `TsColor` values.
778738- The fill pattern of a particular cell can be retrieved by calling the workbook method `ReadBackground`.
779739- The simplified method `WriteBackgroundColor` can be used to achieve a uniform background color.
780740- **Limitations:**
781741 - OpenDocument files support only uniform fills. The background color is a mixture of the foreground and background rgb components in a ratio defined by the fill pattern.
782742 - BIFF2 files support only a 12.5% black-and-white shaded pattern.
783743
784744``` pascal
785745type
786746 TsWorksheet = class
787747 public
788748 function WriteBackground(ARow, ACol: Cardinal; AStyle: TsFillStyle; APatternColor, ABackgroundColor: TsColor): PCell; overload;
789749 procedure WriteBackground(ACell: PCell; AStyle: TsFillStyle; APatternColor, ABackgroundColor: TsColor); overload;
790750
791751 function WriteBackgroundColor(ARow, ACol: Cardinal; AColor: TsColor): PCell; overload;
792752 procedure WriteBackgroundColor(ACell: PCell; AColor: TsColor); overload;
793753
794754 function ReadBackground(ACell: PCell): TsFillPattern;
795755 function ReadBackgroundColor(ACell: PCell): TsColor; overload;
796756 // ...
797757 end;
798758
799759var
800760 cell: PCell;
801761...
802762 // Example 1: Assign a pattern of thin, horizontal, yellow stripes on a blue background to empty cell A1 (row 0, column 0)
803763 MyWorksheet.WriteBackground(0, 0, fsThinStripeHor, scYellow, scBlue);
804764
805765 // Example 2: Uniform gray background color of cell B1 (row 0, column 1) containing the number 3.14
806766 cell := MyWorksheet.WriteNumber(0, 1, 3.14);
807767 MyWorksheet.WriteBackgroundColor(cell, clSilver);
808768```
809769
810770#### Cell borders
811771
812772Cells can be emphasized by drawing border lines along their edges or diagonal lines. There are four borders plus two diagonals enumerated in the data type `TsCellBorder`:
813773
814774``` pascal
815775type
816776 TsCellBorder = (cbNorth, cbWest, cbEast, cbSouth, dbDiagUp, dbDiagDown);
817777 TsCellBorders = set of TsCellBorder;
818778```
819779
820780In 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:
821781
822782``` pascal
823783 MyWorksheet.WriteBorders(0, 0, [cbNorth, cbSouth]); // A1: row 0, column 0
824784 MyWorksheet.WriteBorders(0, 1, [cbNorth, cbSourth]); // B1: row 0, column 1
825785```
826786
827787Lines usually are drawn as thin, solid, black lines. But it is possible to modify **line style** and **color** of each line. For this purpose, the cell provides an array of `TsCellBorderStyle` records:
828788
829789``` pascal
830790type
831791 TsLineStyle = (lsThin, lsMedium, lsDashed, lsDotted, lsThick, lsDouble, lsHair,
832792 lsMediumDash, lsDashDot, lsMediumDashDot, lsDashDotDot, lsMediumDashDotDot, lsSlantDashDot);
833793
834794 TsCellBorderStyle = record
835795 LineStyle: TsLineStyle;
836796 Color: TsColor;
837797 end;
838798
839799 TsCellBorderStyles = array[TsCellBorder] of TsCellBorderStyle;
840800
841801 TsWorksheet = class
842802 public
843803 function WriteBorderStyle(ARow, ACol: Cardinal; ABorder: TsCellBorder; AStyle: TsCellBorderStyle): PCell; overload;
844804 procedure WriteBorderStyle(ACell: PCell; ABorder: TsCellBorder; AStyle: TsCellBorderStyle); overload;
845805
846806 function WriteBorderStyle(ARow, ACol: Cardinal; ABorder: TsCellBorder; ALineStyle: TsLineStyle; AColor: TsColor): PCell; overload;
847807 procedure WriteBorderStyle(ACell: PCell; ABorder: TsCellBorder; ALineStyle: TsLineStyle; AColor: TsColor); overload;
848808
849809 function WriteBorderColor(ARow, ACol: Cardinal; ABorder: TsCellBorder; AColor: TsColor): PCell; overload;
850810 proceure WriteBorderColor(ACell: PCell; ABorder: TsCellBorder; AColor: TsColor): PCell; overload;
851811
852812 function WriteBorderLineStyle(ARow, ACol: Cardinal; ABorder: TsCellBorder; ALineStyle: TsLineStyle): PCell; overload;
853813 procedure WriteBorderLineStyle(ACell: PCell; ABorder: TsCellBorder; ALineStyle: TsLineStyle): PCell; overload;
854814
855815 function WriteBorderStyles(ARow, ACol: Cardinal; const AStyles: TsCellBorderStyles): PCell; overload;
856816 procedure WriteBorderStyles(ACell: PCell; const AStyles: TsCellBorderStyles); overload;
857817
858818 function WriteBorders(ARow, ACol: Cardinal; ABorders: TsCellBorders): PCell; overload
859819 procedure WriteBorders(ACell: PCell; ABorders: TsCellBorders); overload
860820
861821 function ReadCellBorders(ACell: PCell): TsCellBorders;
862822 function ReadCellBorderStyle(ACell: PCell; ABorder: TsCellBorder): TsCellBorderStyle;
863823 function ReadCellBorderStyles(ACell: PCell): TsCellBorderStyles;
864824 ...
865825 end;
866826```
867827
868828The style of a given cell border can be specified by the following methods provided by the worksheet:
869829
870830- **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.
871831- **WriteBorderColor** changes the color of a given border without affecting the line style of this border.
872832- **WriteBorderLineStyle** sets the line style of the border only, but leaves the color unchanged.
873833- **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.
874834
875835This example adds a thin black border to the top, and a thick blue border to the bottom of cells A1 and B1:
876836
877837``` pascal
878838var
879839 cellA1, cellB1: PCell;
880840...
881841 cellA1 := MyWorksheet.WriteBorders(0, 0, [cbNorth, cbSouth]); // cell A1: row 0, column 0
882842 MyWorksheet.WriteBorderStyle(cellA1, cbNorth, lsThin, scBlack);
883843 MyWorksheet.WriteBorderStyle(cellA1, cbSouth, lsThick, scBlue);
884844
885845 cellB1 := MyWorksheet.WriteBorders(0, 1, [cbNorth, cbSouth]); // cell B1: row 0, column 1
886846 MyWorksheet.WriteBorderStyles(cellB1, cellA1^.BorderStyles); // copy all border styles from cell A1 to B1
887847```
888848
889849> **Note:** Diagonal lines are not supported by *sfExcel2* and *sfExcel5* - they are just omitted. *sfExcel8* and *sfOOXML* use the same linestyle and color for both diagonals; when writing the border style of the diagonal-up line is assumed to be valid also for the diagonal-down line. Some writers do not support all the line styles of the `TsLineStyle` enumeration. In this case, appropriate replacement line styles are used.
890850
891851#### Fonts
892852
893853The cell text can displayed in various fonts. For this purpose, the workbook provides a list of `TsFont` items:
894854
895855``` pascal
896856type
897857 TsFont = class
898858 FontName: String;
899859 Size: Single;
900860 Style: TsFontStyles;
901861 Color: TsColor;
902862 Position: TsFontPosition;
903863 end;
904864```
905865
906866- The **FontName** corresponds to the name of the font as used by the operational system. In Windows, an example would be "Times New Roman".
907867- The **FontSize** is given in "points", i.e. units 1/72 inch which are commonly used in Office applications.
908868- The **FontStyle** 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.
909869- The **Color** determines the foreground color of the text characters given in rgb presentation as discussed above.
910870- The **Position** is either `fpNormal`, `fpSuperscript`, or `fpSubscript` and indicates whether the font size should be decreased by about 1/3 and the characters should be displaced up (superscript) or down (subscript).
911871
912872Every cell is provided with an **index into the font list**.
913873
914874In order to assign a particular font to a cell, use one of the following methods of `TsSpreadsheet`:
915875
916876``` pascal
917877type
918878 TsSpreadsheet = class
919879 public
920880 function WriteFont(ARow, ACol: Cardinal; const AFontName: String;
921881 AFontSize: Single; AFontStyle: TsFontStyles; AFontColor: TsColor): Integer; overload;
922882 procedure WriteFont(ARow, ACol: Cardinal; AFontIndex: Integer); overload;
923883 function WriteFontColor(ARow, ACol: Cardinal; AFontColor: TsColor): Integer;
924884 function WriteFontSize(ARow, ACol: Cardinal; ASize: Integer): Integer;
925885 function WriteFontStyle(ARow, ACol: Cardinal; AStyle: TsFontStyles): Integer;
926886 // plus: overloaded versions accepting a pointer to a cell record instead of the row and column index as parameter
927887 // ...
928888 end;
929889```
930890
931891- **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.
932892- **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.
933893- **WriteFontSize** replaces the size of the currently used font of the cell.
934894- **WriteFontStyle** replaces the style (normal, bold, italic, etc.) of the currently used cell font.
935895
936896The 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.
937897
938898The 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`.
939899
940900Here is an **example** which decreases the size of all 10-point "Arial" fonts to 9-point:
941901
942902``` pascal
943903var
944904 i: Integer;
945905 font: TsFont;
946906begin
947907 for i := 0 to MyWorkbook.GetFontCount-1 do
948908 begin
949909 font := MyWorkbook.GetFont(i);
950910 if (font.FontName = 'Arial') and (font.Size = 10.0) then
951911 font.Size := 9.0;
952912 end;
953913end;
954914```
955915
956916#### Rich-text formatting
957917
958918In addition to using a specific font for each cell it is also possible to specify particular font attributes for individual characters or groups of characters in each cell text. Following the Excel notation, we call this feature **Rich-text formatting** (although is has nothing in common with the "rich-text" file format).
959919
960920For this purpose, unit *fpstypes* declares the type `TsRichTextParams` which is an array of `TsRichTextParam` records:
961921
962922``` pascal
963923type
964924 TsRichTextParam = record
965925 FontIndex: Integer;
966926 FirstIndex: Integer;
967927 end;
968928
969929 TsRichTextParams = array of TsRichTextParam;
970930```
971931
972932`FontIndex` refers to the index of the font in the workbook's FontList to be used for formatting of the characters beginning at the index `FirstIndex`. Being a string character index the `FirstIndex` is 1-based.
973933
974934There are two ways to add "rich-text" formatting to a cell text:
975935
976936- Embed corresponding HTML format codes into the cell text. This can be done using the method `WriteTextAsHTML` of the worksheet. In order to add the text "Area (m<sup>2</sup>)" to cell A1, pass the following HTML-coded string to this function
977937
978938``` pascal
979939 MyWorksheet.WriteTextAsHTML(0, 0, 'Area (m<sup>2</sup>');
980940```
981941
982942- Alternatively, the standard text writing method, `WriteText` can be called with an additional parameter specifiying the rich-text formatting parameters to be used directly:
983943
984944``` pascal
985945var
986946 richTextParams: TsRichTextParams;
987947 fnt: TsFont;
988948begin
989949 SetLength(rtp, 2);
990950 fnt := MyWorksheet.ReadCellFont(0, 0);
991951 richTextParams[0].FirstIndex := 8; // The superscript groups begins with "2" which is the (1-based) character #8 of the cell text.
992952 richTextParams[0].FontIndex := MyWorkbook.AddFont(fnt.FontName, fnt.Size, fnt.Style, fnt.Color, fpSuperscript);
993953 richTextParams[1].FirstIndex := 9; // Normal font again beginning with character #9.
994954 richTextParams[1].FontIndex := MyWorksheet.ReadCellFontIndex(0, 0);
995955 MyWorksheet.WriteUTF8Text(0, 0, 'Area (m2)', richTextParams);
996956end;
997957```
998958
999959Use the worksheet method `DeleteRichTextParams` to remove rich-text formatting from a previously formatted cell.
1000960
1001961> **Note:** If the cell is supposed to have a font different from the worksheet's default font then this font must be written to the cell **before** writing the rich-text formatted text. Otherwise the font in the unformatted regions will not be up-to-date.
1002962
1003963#### Text rotation
1004964
1005965Usually 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 to stack horizontal characters vertically above each other.
1006966
1007967If you need this feature use the worksheet method `WriteTextRotation` and specify the text direction by an element of the enumeration type `TsTextRotation`:
1008968
1009969``` pascal
1010970type
1011971 TsTextRotation = (trHorizontal, rt90DegreeClockwiseRotation,
1012972 rt90DegreeCounterClockwiseRotation, rtStacked);
1013973
1014974 TsWorksheet = class
1015975 public
1016976 function WriteTextRotation(ARow, ACol: Cardinal; ARotation: TsTextRotation): PCell; overload;
1017977 procedure WriteTextRotation(ACell: PCell; ARotation: TsTextRotation); overload;
1018978
1019979 function ReadTextRotation(ACell: PCell): TsTextRotation;
1020980 // ...
1021981 end;
1022982
1023983 // example for counter-clockwise rotated text in cell A1:
1024984 WriteTextRotation(0, 0, rt90DegreeCounterClockwizeRotation);
1025985```
1026986
1027987> **Warning:** Finer degrees of rotation which may be supported by some spreadsheet file formats are ignored.
1028988
1029989#### Text alignment
1030990
1031991By 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`:
1032992
1033993``` pascal
1034994type
1035995 TsHorAlignment = (haDefault, haLeft, haCenter, haRight);
1036996 TsVertAlignment = (vaDefault, vaTop, vaCenter, vaBottom);
1037997
1038998 TsWorkbook = class
1039999 public
10401000 function WriteHorAlignment(ARow, ACol: Cardinal; AValue: TsHorAlignment): PCell; overload;
10411001 procedure WriteHorAlignment(ACell: PCell; AValue: TsHorAlignment); overload;
10421002 function ReadHorAlignment(ACell: PCell): TsHorAlignment;
10431003
10441004 function WriteVertAlignment(ARow, ACol: Cardinal; AValue: TsVertAlignment): PCell; overload;
10451005 procedure WriteVertAlignment(ACell: PCell; AValue: TsVertAlignment); overload;
10461006 function ReadVertAlignment(ACell: PCell): TsVertAlignment;
10471007 // ...
10481008 end;
10491009
10501010 // Example: Center the text in cell A1 both horizontally and vertically
10511011 MyWorkbook.WriteHorAlignment(0, 0, haCenter);
10521012 MyWorkbook.WriteVertAlignment(0, 0, vaCenter);
10531013```
10541014
10551015#### Word wrap
10561016
10571017Text which is longer than the width of a cell can wrap into several lines by calling the method `WriteWordwrap` of the spreadsheet:
10581018
10591019``` pascal
10601020type
10611021 TsWorksheet = class
10621022 public
10631023 function WriteWordwrap(ARow, ACol: Cardinal; AValue: Boolean): PCell; overload;
10641024 procedure WriteWordwrap(ACell: PCell; AValue: Boolean); overload;
10651025 function ReadWordwrap(ACell: PCell): Boolean;
10661026 //...
10671027 end;
10681028
10691029 // Example: activate wordwrap in cell A1
10701030 MyWorksheet.WriteWordwrap(0, 0, true);
10711031```
10721032
10731033#### Merged cells
10741034
10751035Like the Office applications, FPSpreadsheet supports also to feature of merging cells to a single large cell which is often used as a common header above simlar columns. Simply call `MergeCells` and pass a parameter to specify the cell range to be merged, either an Excel range string (such as `A1:D5`), or the first and last rows and columns:
10761036
10771037``` pascal
10781038 MyWorksheet.MergeCells('A1:D5');
10791039 // or: MyWorksheet.MergeCells(0, 0, 4, 3); // first row, first column, last row, last column
10801040```
10811041
10821042The content and format displayed for a merged range is taken from the upper left corner of the range, cell `A1` in above example. This cell is called the `MergeBase` in the library. Except for this corner cell, there must not be any other cells in the range. If there are their contents and format will be hidden.
10831043
10841044In order to break up a merged range back up into individual cells, use the command `Unmerge` and pass any cell that is within the merged range:
10851045
10861046``` pascal
10871047 MyWorksheet.UnmergeCells('B1');
10881048 // or: MyWorksheet.UnmergeCells(0, 1); // row, column of any cell within the range
10891049```
10901050
10911051Merged cells can be read from/written to all file formats except for `sfCSV`, `sfExcel2` and `sfExcel5` which do not support this feature natively.
10921052
10931053The information which cells are merged is stored in an internal list. Unlike in earlier versions it is no longer possible to access the `MergeBase` from the cell directly. Use the following functions to extract information on merged cells:
10941054
10951055``` pascal
10961056var
10971057 cell, base: PCell;
10981058 r1,c1,r2,c2: Cardinal;
10991059...
11001060 cell := MyWorksheet.FindCell('B1');
11011061 if MyWorksheet.IsMerged(cell) then
11021062 begin
11031063 WriteLn('Cell B1 is merged.');
11041064
11051065 MyWorksheet.FindMergedRange(cell, r1, c1, r2, c2);
11061066 WriteLn('The merged range is ' + GetCellRangeString(r1, c1, r2, c2));
11071067
11081068 base := MyWorksheet.FindMergeBase(cell);
11091069 WriteLn('The merge base is cell ' + GetCellString(base^.Row, base^.Col));
11101070 end;
11111071```
11121072
11131073### Additional data
11141074
11151075#### Cell comments
11161076
11171077Comments can be attached to any cell by calling
11181078
11191079``` pascal
11201080 MyWorksheet.WriteComment(0, 0, 'This is a comment for cell A1');
11211081```
11221082
11231083They are stored in an internal list of the worksheet. Use the corresponding worksheet methods to access comments:
11241084
11251085- If you want to know whether a particular cell contains a comment call the worksheet method `HasComment(cell)`.
11261086- For retrieving a cell comment use the method `ReadComment(cell)`, or its overloaded companion `ReadComment(ARow, ACol)`.
11271087- The total number of comments can be retrieved from `worksheet.Comments.Count`.
11281088
11291089#### Hyperlinks
11301090
11311091Hyperlinks can be attached to cells in order to link cells to other documents or other cells in the same workbook. The general syntax for creating hyperlinks is
11321092
11331093``` pascal
11341094 procedure TWorksheet.WriteHyperlink(ARow, ACol: Cardinal; ATarget: String; ATooltip: String = '');
11351095```
11361096
11371097- The hyperlink target, passed as parameter `ATarget`, must be a fully qualified [URI (Uniform resource identifier)](http://en.wikipedia.org/wiki/Uniform_Resource_Identifier) consisting of a protocol phrase (e.g., [`http://`](http://), [`file:///`](file:///), `mailto:`, etc.) followed by specific information such as web URL, filename, or e-mail address and an optional bookmark identification separated by the character `'#'`. An exception are internal hyperlinks which enable to jump to a cell in the current workbook; they consist of the optional worksheet name and the cell address separated by the character `'!'`.
11381098- The optional `Tooltip` parameter is evaluated by Excel to display it in a hint window if the mouse if above the hyperlink.
11391099
11401100> **Note:** Hyperlinks can be added to empty cells or to cells with content. In the latter case, the displayed content is not changed by the hyperlink; in the former case the cell is converted to a label cell showing the hyperlink target. Be aware that OpenOffice/LibreOffice only does accept hyperlinks with non-text cells.
11411101
11421102**Examples:**
11431103
11441104``` pascal
11451105 // Open the web site www.google.com
11461106 MyWorksheet.WriteText(0, 0, 'Open google');
11471107 MyWorksheet.WriteHyperlink(0, 0, 'http://www.google.com');
11481108
11491109 // Open the local file with the absolute path "C:\readme.txt" (assuming Windows)
11501110 MyWorksheet.WriteHyperlink(1, 0, 'file:///c:\readme.txt');
11511111
11521112 // Open the mail client to send a mail
11531113 MyWorksheet.WriteText('Send mail');
11541114 MyWorksheet.WriteHyperlink(3, 0, 'mailto:somebody@gmail.com?subject=Test');
11551115
11561116 // Jump to a particular cell
11571117 MyWorksheet.WriteText(5, 0, 'Jump to cell A10 on sheet2');
11581118 MyWorksheet.WriteHyperlink(5, 0, '#Sheet2!A10');
11591119
11601120 // Jump to cell A10 on the current sheet and display a popup hint
11611121 MyWorksheet.WriteHyperlink(5, 0, '#A10', 'Go to cell A10');
11621122```
11631123
11641124> **Note:** FPSpreadsheet does not "follow" the links, it only provides a mechanism to get access to the link data. TsWorksheetGrid from the *laz_fpspreadsheet_visual* package, however, fires the event `OnClickHyperlink` if a cell with an external hyperlink is clicked for fractions of a second. In the corresponding event handler, you can, for example, load a target spreadsheet, or open a web browser to display the linked web site. If the link is an internal link to another cell within the same workbook then the grid jumps to the related cell.
11651125
11661126#### Images
11671127
11681128FPSpreadsheet supports embedding of images in worksheets. Use one of the worksheet methods `WriteImage()` to add an image to the worksheet:
11691129
11701130``` pascal
11711131 MyWorksheet.WriteImage(row, col, filename, offsetX, offsetY, scaleX, scaleY);
11721132 MyWorksheet.WriteImage(row, col, stream, offsetX, offsetY, scaleX, scaleY);
11731133 MyWorksheet.WriteImage(row, col, imageindex, offsetX, offsetY, scaleX, scaleY);
11741134```
11751135
11761136The upper/left corner of the image is placed at the upper/left corner of the cell in the specified row and column. The floating point parameters `offsetX`, `offsetY`, `scaleX` and `scaleY` are optional: they define an offset of this image anchor point from the cell corner and a magnification factor. The path to the image file is given as parameter `filename`. Alternatively, overloaded versions can be used which accept a stream in place of the file name or an image index in the workbook's EmbeddedObj list - use `MyWorkbook.FindEmbeddedObj(filename)` to get this index for a previously loaded image file.
11771137
11781138Note that FPSpreadsheet needs to know the image type for successfull picture import. Currently, the types *png*, *jpg*, *tiff*, *bmp*, *gif*, *svg*, *wmf*, *emf*, and *pcx* are supported (Excel2007 cannot read imported *svg* and *pcx* images). Other formats can be registered by writing a function which determines the image size and pixel density, and by registering the new format using the procedure `RegisterImageType` - see unit *fpsImages* for examples:
11791139
11801140``` pascal
11811141type
11821142 TsImageType = integer;
11831143 TGetImageSizeFunc = function (AStream: TStream; out AWidth, AHeight: DWord; out dpiX, dpiY: Double): Boolean;
11841144
11851145function RegisterImageType(AMimeType, AExtension: String; AGetImageSize: TGetImageSizeFunc): TsImageType;
11861146```
11871147
11881148Due to differences in row height and column width calculation between FPSpreadsheet and Office applications it is not possible to position images correctly. If exact image positions are important you should follow these rules:
11891149
11901150- Predefine the widths of all columns at least up to the one containing the right edge of the image.
11911151- Predefine the heights of all rows at least up to the one containing the lower edge of the image.
11921152- If the workbook is to be saved in OpenDocument format add the image after changing column widths and row heights because ods anchors the image to the sheet, not to the cell (like Excel and FPSpreadsheet).
11931153- If the exact size of the image is important make sure that it fits into a single cell.
11941154
11951155### Sorting
11961156
11971157Cells in a worksheet can be sorted for a variety of criteria by calling the `Sort` method of the worksheet. This method takes a `TsSortParams` record and the edges of the cell rectangle to be sorted as parameters; in an overloaded version, the cell rectangle can also be specified by means of an Excel-type range string (e.g. `'A1:G10'`):
11981158
11991159``` pascal
12001160type
12011161 TsWorksheet = class
12021162 // ...
12031163 procedure Sort(const ASortParams: TsSortParams;
12041164 ARowFrom, AColFrom, ARowTo, AColTo: Cardinal); overload;
12051165 procedure Sort(ASortParams: TsSortParams; ARange: String); overload;
12061166 // ...
12071167 end;
12081168```
12091169
12101170The sorting criteria are defined by a record of type `TsSortParams`:
12111171
12121172``` pascal
12131173type
12141174 TsSortParams = record
12151175 SortByCols: Boolean;
12161176 Priority: TsSortPriority; // spNumAlpha ("Numbers first"), or spAlphaNum ("Text first")
12171177 Keys: TsSortKeys;
12181178 end;
12191179
12201180 TsSortKey = record
12211181 ColRowIndex: Integer;
12221182 Options: TsSortOptions; // set of [spDescending, spCaseInsensitive]
12231183 end;
12241184```
12251185
12261186- The boolean value `SortByCols` determines wether sorting occurs along columns (`true`) or rows (`false`). The `ColRowIndex` specified in the sorting keys, accordingly, corresponds to a column or row index, respectively (see below).
12271187- `Priority` determines in mixed content cell ranges whether an ascending sort puts numerical values in front of text values or not. Empty cells are always moved to the end of the sorted column or row. In Excel, the priority is "numbers first" (`spNumAlpha`).
12281188- The array `Keys` specifies multiple sorting parameters. They consist of the index of the column or row to be sorted (`ColRowIndex`) and a set of `Options` for sorting direction (`spoDescending`) and character case (`spCaseInsensitive`). If `Options` is empty, cell comparison is case-sensitive, and cells are arranged in ascending order. If two cells are found to be "equal" on the basis of the first key (`sortParams.Keys[0]`) comparison proceeds with the next conditions in the `Keys` array until a difference is found or all conditions are used up.
12291189
12301190`InitSortParams` is a handy utility to initialize the sorting parameters:
12311191
12321192``` pascal
12331193function InitSortParams(ASortByCols: Boolean = true; ANumSortKeys: Integer = 1;
12341194 ASortPriority: TsSortPriority = spNumAlpha): TsSortParams;
12351195```
12361196
12371197The next code fragment shows a typical sorting call:
12381198
12391199``` pascal
12401200var
12411201 sortParams: TsSortParams;
12421202begin
12431203 sortParams := InitSortParams(true, 2); // sorting along columns, 2 sorting keys
12441204
12451205 // primary sorting key: column 3, ascending, case-insensitive
12461206 sortParams.Keys[0].ColRowIndex := 3;
12471207 sortParams.Keys[0].Options := [ssoCaseInsensitive];
12481208
12491209 // secondary sorting key: colum 1, descending
12501210 sortParams.Keys[1].ColRowIndex := 1;
12511211 sortParams.Keys[1].Options := [ssoDescending];
12521212
12531213 // The sorted block extends between cells A1 (row=0, col=0) and F10 (row=9, col=5)
12541214 MyWorksheet.Sort(sortParams, 0, 0, 9, 5);
12551215 // or: MyWorksheet.Sort(sortParams, 'A1:F10');
12561216end;
12571217```
12581218
12591219### Searching and replacing
12601220
12611221Unit *fpsSearch* implements a **search engine** which can be used to look for specific cell content within a workbook, or to replace the found cell content by some other string.
12621222
12631223**Example:**
12641224
12651225``` pascal
12661226var
12671227 MyWorkbook: TsWorkbook;
12681228 MyWorksheet: TsWorksheet;
12691229 MyRow, MyCol: Cardinal;
12701230 MySearchParams: TsSearchParams;
12711231begin
12721232 MyWorkbook := TsWorkbook.Create;
12731233 try
12741234 MyWorkbook.ReadFromFile(AFileName);
12751235
12761236 // Specify search criteria
12771237 MySearchParams.SearchText := 'Hallo';
12781238 MySearchParams.Options := [soEntireDocument];
12791239
12801240 // Create search engine and execute search
12811241 with TSearchEngine.Create(MyWorkbook) do begin
12821242 if FindFirst(MySearchParams, MyWorksheet, MyRow, MyCol) then begin
12831243 WriteLn('First "', MySearchparams.SearchText, '" found in cell ', GetCellString(MyRow, MyCol));
12841244 while FindNext(MySeachParams, MyWorksheet, myRow, MyCol) do
12851245 WriteLn('Next "', MySearchParams.SearchText, '" found in cell ', GetCellString(MyRow, MyCol));
12861246 end;
12871247 Free;
12881248 end;
12891249 finally
12901250 MyWorkbook.Free;
12911251 end;
12921252end;
12931253```
12941254
12951255The search engine provides two methods for **searching**: `FindFirst` and `FindNext`. They are very similar, they only differ in where the search begins. In case of `FindFirst`, the starting cell is determined from the `Options` described below. In case of `FindNext` the search begins at the cell adjacent to the previously found cell. Both methods return the worksheet and row and column indexes of the cell in which the search text is found. If the search is not successful then the function result is `FALSE`.
12961256
12971257The record `TsSearchParams` specifies the criteria used for searching:
12981258
12991259``` pascal
13001260type
13011261 TsSearchParams = record
13021262 SearchText: String;
13031263 Options: TsSearchOptions;
13041264 Within: TsSearchWithin;
13051265 end;
13061266```
13071267
13081268Besides the text to be searched (`SearchText`) it provides a set of options to narrow the search:
13091269
13101270- `soCompareEntireCell`: Compares the `SearchText` with the entire cell content. If not contained in the `Options` then the cell text is compared only partially.
13111271- `soMatchCase`: Perform a case-sensitive search
13121272- `soRegularExpr`: The `SearchText` is considered as a regular expression
13131273- `soAlongRows`: The search engine proceeds first along the rows. If not contained in the `Options` then the search proceeds along the columns.
13141274- `soBackward`: The search begins at the end of the document, or runs backward from the active cell. If not contained in the `Options` then the search starts at the beginning of the document, or runs forward from the active cell.
13151275- `soWrapDocument`: If a search has reached the end of the document the search is resumed at its beginning (or vice versa, if `soBackward` is used).
13161276- `soEntireDocument`: Search begins at the first cell (or last cell if `soBackward` is used). If not contained in the `Options` then the search begins at the active cell of the worksheet. Ignored by `FindNext`.
13171277
13181278The record field `Within` identifies the part of the spreadsheet to be searched:
13191279
13201280- `swWorkbook`: The entire workbook is searched. If the search phrase is not found on the first worksheet (or last worksheet if `soBackward` is used) then the search continues with the next (previous) sheet.
13211281- `swWorksheet`: The search is limited to the currently active worksheet
13221282- `swColumn`: Search is restricted to the column of the active cell
13231283- `swRow`: Search is restricted to the row of the active cell.
13241284
13251285In addition to searching the search engine can also be used for **replacing** the found text by another string. Call the functions `ReplaceFirst` or `ReplaceNext` for this purpose. They act like their `FindXXXX` counterparts, therefore, they require a `TsSearchParams` record to specify the search criteria. But in addition to searching, these functions also perform the text replacement according to the specification in a `TsReplaceParams` record:
13261286
13271287``` pascal
13281288type
13291289 TsReplaceParams = record
13301290 ReplaceText: String;
13311291 Options: TsReplaceOptions;
13321292 end;
13331293```
13341294
13351295The `ReplaceText` identifies the string which will replace the found text pattern. The `Options` define a set of criteria how the replacement is done:
13361296
13371297- `roReplaceEntirecell`: Replaces the entire cell text by the `ReplaceText`. If not contained in the `Options` then only the part matching the `SearchText` is replaced.
13381298- `roReplaceAll`: Performs the replacement in all found cells (i.e., simply call `ReplaceFirst` to replace all automatically).
13391299- `roConfirm`: Calls an event handler for the `OnConfirmReplacement` event in which the user must specify whether the replacement is to be performed or not. Note that this event handler is mandatory if `roConfirm` is set.
13401300
13411301### Column and row operations
13421302
13431303The worksheet provides these methods for inserting and deleting columns a row:
13441304
13451305``` pascal
13461306type
13471307 TsWorksheet = class
13481308 ...
13491309 procedure DeleteCol(ACol: Cardinal);
13501310 procedure DeleteRow(ARow: Cardinal);
13511311
13521312 procedure InsertCol(ACol: Cardinal);
13531313 procedure InsertRow(ARow: Cardinal);
13541314
13551315 procedure RemoveCol(ACol: Cardinal);
13561316 procedure RemoveRow(ARow: Cardinal);
13571317
13581318 procedure RemoveAllCols;
13591319 procedure RemoveAllRows
13601320```
13611321
13621322- When a column or row is **deleted** by DeleteCol\</t\> or `DeleteRow`, any data assigned to this column or row are removed, i., cells, comments, hyperlinks, TCol or TRow records. Data at the right of or below the deleted column/row move to the left or up.
13631323
13641324- `RemoveCol` and `RemoveRow`, in contract, **remove** only the column or row record, i.e. reset column width and row height to their default values. Cell, comment, and hyperlink data are not affected.
13651325
13661326- `RemoveAllCols` **removes all** column records, i.e. resets all column widths; `RemoveAllRows` does the same with the row records and row heights.
13671327
13681328- A column or row is **inserted** before the index specified as parameter of the `InsertXXX` method.
13691329
13701330### Page layout
13711331
13721332#### General
13731333
13741334So far, FPSpreadsheet does not support printing of worksheets, but the Office applications do, and they provide a section of information in their files for this purpose. In FPSpreadsheets this information is available in the `TsPageLayout` class which belongs to the `TsWorksheet` data structure. Its properties and methods combine the most important features from the Excel and OpenDocument worlds.
13751335
13761336``` pascal
13771337type
13781338 TsPageOrientation = (spoPortrait, spoLandscape);
13791339
13801340 TsPrintOption = (poPrintGridLines, poPrintHeaders, poPrintPagesByRows,
13811341 poMonochrome, poDraftQuality, poPrintCellComments, poDefaultOrientation,
13821342 poUseStartPageNumber, poCommentsAtEnd, poHorCentered, poVertCentered,
13831343 poDifferentOddEven, poDifferentFirst, poFitPages);
13841344
13851345 TsPrintOptions = set of TsPrintOption;
13861346
13871347 TsHeaderFooterSectionIndex = (hfsLeft, hfsCenter, hfsRight);
13881348
13891349 TsCellRange = record
13901350 Row1, Col1, Row2, Col2: Cardinal;
13911351 end;
13921352
13931353 TsPageLayout = class
13941354 ...
13951355 public
13961356 ...
13971357 { Methods }
13981358 // embedded header/footer images
13991359 procedure AddHeaderImage(AHeaderIndex: Integer;
14001360 ASection: TsHeaderFooterSectionIndex; const AFilename: String);
14011361 procedure AddFooterImage(AFooterIndex: Integer;
14021362 ASection: TsHeaderFooterSectionIndex; const AFilename: String);
14031363 procedure GetImageSections(out AHeaderTags, AFooterTags: String);
14041364 function HasHeaderFooterImages: Boolean;
14051365
14061366 // Repeated rows and columns
14071367 function HasRepeatedCols: Boolean;
14081368 function HasRepeatedRows: Boolean;
14091369 procedure SetRepeatedCols(AFirstCol, ALastCol: Cardinal);
14101370 procedure SetRepeatedRows(AFirstRow, ALastRow: Cardinal);
14111371
14121372 // print ranges
14131373 function AddPrintRange(ARow1, ACol1, ARow2, ACol2: Cardinal): Integer; overload;
14141374 function AddPrintRange(const ARange: TsCellRange): Integer; overload;
14151375 function GetPrintRange(AIndex: Integer): TsCellRange;
14161376 function NumPrintRanges: Integer;
14171377 procedure RemovePrintRange(AIndex: Integer);
14181378
14191379 { Properties }
14201380 property Orientation: TsPageOrientation read FOrientation write FOrientation;
14211381 property PageWidth: Double read FPageWidth write FPageWidth;
14221382 property PageHeight: Double read FPageHeight write FPageHeight;
14231383 property LeftMargin: Double read FLeftMargin write FLeftMargin;
14241384 property RightMargin: Double read FRightMargin write FRightMargin;
14251385 property TopMargin: Double read FTopMargin write FTopMargin;
14261386 property BottomMargin: Double read FBottomMargin write FBottomMargin;
14271387 property HeaderMargin: Double read FHeaderMargin write FHeaderMargin;
14281388 property FooterMargin: Double read FFooterMargin write FFooterMargin;
14291389 property StartPageNumber: Integer read FStartPageNumber write SetStartPageNumber;
14301390 property ScalingFactor: Integer read FScalingFactor write SetScalingFactor;
14311391 property FitHeightToPages: Integer read FFitHeightToPages write SetFitHeightToPages;
14321392 property FitWidthToPages: Integer read FFitWidthToPages write SetFitWidthToPages;
14331393 property Copies: Integer read FCopies write FCopies;
14341394 property Options: TsPrintOptions read FOptions write FOptions;
14351395 property Headers[AIndex: Integer]: String read GetHeaders write SetHeaders;
14361396 property Footers[AIndex: Integer]: String read GetFooters write SetFooters;
14371397 property RepeatedCols: TsRowColRange read FRepeatedCols;
14381398 property RepeatedRows: TsRowColRange read FRepeatedRows;
14391399 property PrintRange[AIndex: Integer]: TsCellRange read GetPrintRange;
14401400 property FooterImages[ASection: TsHeaderFooterSectionIndex]: TsHeaderFooterImage read GetFooterImages;
14411401 property HeaderImages[ASection: TsHeaderFooterSectionIndex]: TsHeaderFooterImage read GetHeaderImages;
14421402 end;
14431403
14441404 TsWorksheet = class
14451405 ...
14461406 public
14471407 property PageLayout: TsPageLayout;
14481408 ...
14491409 end;
14501410```
14511411
14521412> **Note:** The fact that the `PageLayout` belongs to the worksheet indicates that there can be several page layouts in the same workbook, one for each worksheet.
14531413
14541414- **Orientation** defines the orientation of the printed paper, either portrait or landscape.
14551415
14561416- **Page width** and **page height** refer to the standard orientation of the paper, usually portrait orientation.
14571417
14581418- **Left**, **top**, **right** and **bottom margins** are self-explanatory and are given in millimeters.
14591419
14601420- **HeaderMargin** is understood - like in Excel - as the distance between the paper top edge and the top of the header, and **TopMargin** correspondingly is the distance between the top paper edge and the top of the first table row, i.e. if the header contains several line breaks it can reach into the the table part of the print-out. This is different from OpenDocument files where the header can grow accordingly.
14611421
14621422- **StartPageNumber** should be altered if the print-out should not begin with page 1. This setting requires to add the option `poUseStartPageNumber` to the PageLayout's `Options` - but this is normally done automatically.
14631423
14641424- The **ScalingFactor** is given in percent and can be used to reduce the number of printed pages. Modifying this property clear the option `poFitToPages` from the PageLayout's `Options`.
14651425
14661426- Alternatively to ScalingFactor, you can also use **FitHeightToPages** or **FitWidthToPages**. The option `poFitToPages` must be active in order to override the `ScalingFactor`setting. `FitHeightToPages` specifies the number of pages onto which the entire height of the printed worksheet should fit. Accordingly, `FitWidthToPages` can be used to define the number of pages on which the entire width of the worksheet has to fit. The value `0` has the special meaning of "use as many pages as needed". In this way, the setting "Fit all columns on one page" of Excel, for example, can be achieved by this code:
14671427
14681428``` pascal
14691429 MyWorksheet.PageLayout.Options := MyWorksheet.PageLayout.Options + [poFitPages];
14701430 MyWorksheet.PageLayout.FitWidthToPages := 1; // all columns on one page width
14711431 MyWorksheet.PageLayout.FitHeightToPages := 0; // use as many pages as needed
14721432```
14731433
14741434- **Header rows and columns repeated on every printed page** can be defined by the `RepeatedCols` and `RepeatedRows` records; their elements `FirstIndex` and `LastIndex` refer to the indexes of the first and last column or row, respectively, to be repeated. Use the methods `SetRepeatedCols` and `SetRepeatedRows` to define these numbers. Note that the second parameter for the last index can be omitted to use only a single header row or column.
14751435
14761436- **Print ranges** or **print areas** (using Excel terminology) can be used to restrict printing only to a range of cells. Use the methods `AddPrintRange` to define a cell range for printing: specify the indexes of the left column, top row, right column and bottom row of the range to be printed. A worksheet can contain several print ranges.
14771437
14781438- **Copies** specifies how often the worksheet will be printed.
14791439
14801440- The **Options** define further printing properties, their names are self-explaining. They were defined according to Excel files, some of them do not exist in ODS files and are ignored there.
14811441
14821442#### Headers and footers
14831443
14841444**Header and footer texts** can be composed of left-aligned, centered and right-aligned strings. Add the symbol `&L` to indicate that the following string is to be printed as the left-aligned part; use `&C` accordingly for the centered and `&R` for the right-aligned parts. There are other symbols which will be replaced by their counterparts during printing:
14851445
14861446- `&L`: begins the **left-aligned section** of a header or a footer text definition
14871447- `&C`: begins the **centered section** of a header or a footer text definition
14881448- `&R`: begins the **right-aligned section** of a header or a footer text definition
14891449- `&P`: **page number**
14901450- `&N`: **page count**
14911451- `&D`: current **date** of printing
14921452- `&T`: current **time** of printing
14931453- `&A`: **worksheet name**
14941454- `&F`: **file name** without path
14951455- `&P`: **file path** without file name
14961456- `&G`: embedded **image** - use the methods `AddHeaderImage` or `AddFooterImage` to specify the image file; this also appends the `&G` to the other codes of the current header/footer section. Note that not all image types known by the Office application may be accepted. Currently the image can be *jpeg*, *png*, *gif*, *bmp*, *tiff*, *pcx*, *svg*, *wmf* or *emf*.
14971457- `&B`: **bold** on/off
14981458- `&I`: **italic** on/off
14991459- `&U`: **underlining** on/off
15001460- `&E`: **double-underlining** on/off
15011461- `&S`: **strike-out** on/off
15021462- `&H`: **shadow** on/off
15031463- `&O`: **outline** on/off
15041464- `&X`: **superscript** on/off
15051465- `&Y`: **subscript** on/off
15061466- `&"font"`: begin using of the **font** with the specified name, e.g. `&"Arial"`
15071467- `&number`: begin using of the specified **font size** (in points), e.g. `&16`
15081468- `&Krrggbb`: switch to the **font color** specified to the binary value of the specified color, e.g. use `&KFF0000` for red.
15091469
15101470The arrays `Headers[]`/`Footers[]` provide space for usage of three different headers or footers:
15111471
15121472- `Headers[0]` refers to the header used on the **first page** only, similarly for `Footers[0]`. Instead of index `0` you can use the constant `HEADER_FOOTER_INDEX_FIRST`. Leave this string empty if there is no special first-page header/footer.
15131473- `Headers[1]` refers to the header on pages with **odd page numbers**, similarly for `Footers[1]`. Instead of index `1` you may want to use the constant `HEADER_FOOTER_INDEX_ODD`.
15141474- `Headers[2]` refers to the header on lages with **even page nubmers**, similarly for `Footers[2]`. Instead of index `2` you may want to use the constant `HEADER_FOOTER_INDEX_EVEN`.
15151475
15161476Leave the strings at index 0 and 2 empty if the print-out should always have the same header/footer. You can use the constant `HEADER_FOOTER_INDEX_ALL` for better clarity. Example:
15171477
15181478``` pascal
15191479 MyWorksheet.PageLayout.Headers[HEADER_FOOTER_INDEX_ALL] := '&C&D &T'; // centered "date time" on all pages as header
15201480 MyWorksheet.PageLayout.Footers[HEADER_FOOTER_INDEX_ODD] := '&RPage &P of &N'; // right-aligned "Page .. of ..." on odd pages as footer
15211481 MyWorksheet.PageLayout.Footers[HEADER_FOOTER_INDEX_EVEN] := '&LPage &P of &N'; // dto, but left-aligned on even pages
15221482```
15231483
15241484### Loading and saving
15251485
15261486#### Adding new file formats
15271487
15281488FPSpreadsheet is open to any spreadsheet file format. In addition to the built-in file formats which are specified by one of the `sfXXXX` declarations, it is possible to provide dedicated reader and writer units to get access to special file formats.
15291489
15301490- Write a unit implementing a reader and a writer for the new file format. They must inherit from the basic `TsCustomSpreadReader` and `TsCustomWriter`, respectively, - both are implemented in unit *fpsReaderWriter* -, or from one of the more advanced ones belonging to the built-in file formats.
15311491- Register the new reader/writer by calling the function `RegisterSpreadFileFormat` in the `initialization` section of this unit (implemented in unit *fpsRegFileFormats*):
15321492
15331493``` pascal
15341494function RegisterSpreadFormat(AFormat: TsSpreadsheetFormat; AReaderClass: TsSpreadReaderClass; AWriterClass: TsSpreadWriterClass;
15351495 AFormatName, ATechnicalName: String; const AFileExtensions: array of String): TsSpreadFormatID;
15361496```
15371497
15381498- `AFormat` must have the value `sfUser` to register an external file format.
15391499- `AReaderClass` is the class of the reader (or nil, if reading functionality is not implemented).
15401500- `AWriterClass` is the class of the writer (or nil, if writing functionality is not implemented).
15411501- `AFormatName` defines the name of the format as used for example in the filter list of file-open dialogs.
15421502- `ATechnicalName` defines a shorter format name.
15431503- `AFileExtensions` is an array of file extensions used in the files. The first array element denotes the default extension. The extensions must begin with a period as in `.xls`.
15441504- The registration function returns a numerical value (`TsSpreadFormatID`) which can be used as format identifier in the workbook reading and writing functions which exist in overloaded version accepting a numerical value for the format specifier. In contract to the built-in formats the FormatID is negative.
15451505- Finally, in your application, add the new unit to the `uses` clause. This will call the registrations function when the unit is loaded and make the new file format available to FPSpreadsheet.
15461506
15471507#### Stream selection
15481508
15491509Workbooks are loaded and saved by means of the `ReadFromFile` and `WriteToFile` methods, respectively (or by their stream counterparts, `ReadFromStream` and `WriteToStream`).
15501510
15511511By default, the data files are accessed by means of **memory streams** which yields the fastest access to the files. In case of very large files (e.g. tens of thousands of rows), however, the system may run out of memory. There are two methods to defer the memory overflow by some extent.
15521512
15531513- Add the element `boBufStream` to the workbook's `Options`. In this case, a **"buffered" stream** is used for accessing the data. This kind of stream holds a memory buffer of a given size and swaps data to file if the buffer becomes too small.
15541514- Add the element `boFileStream` to the workbook's `Options`. This option avoids memory streams altogether and creates temporary **files** if needed. This is, however, the slowest method of data access.
15551515- If both options are set then `boBufStream` is ignored.
15561516- In practice, however, the effect of the selected streams is not very large if memory is to be saved.
15571517
15581518#### Virtual mode
15591519
15601520Beyond the transient memory usage during reading/writing the main memory consumptions originates in the internal structure of FPSpreadsheet which holds all data in memory. To overcome this limitation, a "virtual mode" has been introduced. In this mode, data are received from a data source (such as a database table) and are passed through to the writer without being collected in the worksheet. It is clear that data loaded in virtual mode cannot be displayed in the visual controls. Virtual mode is good for conversion between different data formats.
15611521
15621522These are the steps required to use this mode:
15631523
15641524- Activate virtual mode by adding the option `boVirtualMode` to the `Options` of the workbook.
15651525- Tell the spreadsheet writer how many rows and columns are to be written. The corresponding worksheet properties are `VirtualRowCount` and `VirtualColCount`.
15661526- Write an event handler for the event `OnWriteCellData` of the worksheet. This handler gets the index of row and column of the cell currently being saved. You have to return the value which will be saved in this cell. You can also specify a template cell that physically exists in the workbook from which the formatting style is copied to the destination cell. Please be aware that when exporting a database, you are responsible for advancing the dataset pointer to the next database record when writing of a row is complete.
15671527- Call the `WriteToFile` method of the workbook.
15681528
15691529Virtual mode also works for reading spreadsheet files.
15701530
15711531The folder *example/other* contains a worked out sample project demonstrating virtual mode using random data. More realistic database examples are in *example/db_import_export* and in the chapter on converting a large database table using virtual mode.
15721532
15731533### Dataset export
15741534
15751535FPC contains a set of units that allow you to export datasets to various formats (XML, SQL statements, DBF files,...). There is a master package that allows you to choose an export format at design time or run time (Lazarus package lazdbexport).
15761536
15771537FPSpreadsheet has `TFPSExport` which plugs into this system. It allows you to export the contents of a dataset to a new spreadsheet (*.xls*, *.xlsx*, *.ods*, wikitable format) file into a table on the first sheet by default. In addition, if `MultipleSheets` is set to `TRUE` it is possible to combine several sheets into individual worksheets in the same file. You can optionally include the field names as header cells on the first row using the `HeaderRow` properties in the export settings. The export component tries to find the number format of the cells according to the dataset field types.
15781538
15791539For more complicated exports, you need to manually code a solution (see examples below) but for simple data transfer/dynamic exports at user request, this unit will probably be sufficient.
15801540
15811541A simple example of how this works:
15821542
15831543``` pascal
15841544uses
15851545...
15861546fpsexport
15871547...
15881548var
15891549 Exp: TFPSExport;
15901550 ExpSettings: TFPSExportFormatSettings;
15911551 TheDate: TDateTime;
15921552begin
15931553 FDataset.First; //assume we have a dataset called FDataset
15941554 Exp := TFPSExport.Create(nil);
15951555 ExpSettings := TFPSExportFormatSettings.Create(true);
15961556 try
15971557 ExpSettings.ExportFormat := efXLS; // choose file format
15981558 ExpSettings.HeaderRow := true; // include header row with field names
15991559 Exp.FormatSettings := ExpSettings; // apply settings to export object
16001560 Exp.Dataset:=FDataset; // specify source
16011561 Exp.FileName := 'c:\temp\datadump.xls';
16021562 Exp.Execute; // run the export
16031563 finally
16041564 Exp.Free;
16051565 ExpSettings.Free;
16061566 end;
16071567```
16081568
16091569## Visual controls for FPSpreadsheet
16101570
16111571The package **laz_fpspreadsheet_visual** implements a series of controls which simiplify creation of visual GUI applications:
16121572
16131573- **TsWorkwookSource** links the controls to a workbook and notifies the controls of changes in the workbook.
16141574- **[[TsWorksheetGrid]]** implements a grid control with editing and formatting capabilities; it can be applied in a similar way to TStringGrid.
16151575- **TsWorkbookTabControl** provides a tab sheet for each worksheet of the workbook. It is the ideal container for a [[TsWorksheetGrid]].
16161576- **TsCellEdit** corresponds to the editing line in Excel or Open/LibreOffice. Direct editing in the grid, however, is possible as well.
16171577- **TsCellIndicator** displays the name of the currently selected cell; it can be used for navigation purposes by entering a cell address string.
16181578- **TsCellCombobox** offers to pick cell properties for a selection of formatting attributes: font name, font size, font color, background color.
16191579- **TsSpreadsheetInspector** is a tool mainly for debugging; it displays various properties of workbook, worksheet, cell value and cell formatting, similar to the ObjectInspector of Lazarus. It is read-only, though.
16201580- Various standard actions are provided in the unit **fpsActions**. Applied to menu or toolbar, they simplify typical formatting and editing tasks without having to write a line of code.
16211581- **TsWorkbookChartSource** interfaces a workbook with the [[TAChart]] library. It defines the cell ranges from which a Chart series can get its data. There is also an older component, [[TsWorksheetChartSource]], which requires all cells to be from the same worksheet. For this reason, it has not been fully integrated into the environment of FPSpreadsheet controls and will be removed from the library in the future.
16221582
16231583See the [[FPSpreadsheet tutorial: Writing a mini spreadsheet application]] for more information and a tutorial, and see demo projects for examples of the application of these components.
16241584
16251585## Examples
16261586
16271587To 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.
16281588
16291589### Units
16301590
16311591The entire FPSpreadsheet package consists of several units. A spreadsheet application typically "uses" the following units:
16321592
16331593- *fpspreadsheet*: implements **TsWorkbook** and **TsWorksheet** and the **basic file reading/writing methods**
16341594- *fpstypes*: declares most of the **data types** and **constants** used throughout the package. **Note:** in older versions these declarations were contained in fpspreadsheet.pas.
16351595- the unit(s) implementing the reader/writer for a given **file format**, e.g. *xlsbiff8* for binary Excel files. If the application will be able to handle all formats "use" the unit *fpsallformats*.
16361596
16371597The next units are required only occasionally:
16381598
16391599- *fpsutils*: a collection of **utility functions** that are occasionally needed (e.g. conversion of col/row indexes to Excel-like cell address string).
16401600- *fpscell*: this unit is required if you use **direct cell formatting** (e.g. `cell^.BackgroundColor := scYellow`) instead of calling the corresponding worksheet method (`MyWorksheet.WriteBackgroundColor(cell, scYellow)`, in this example).
16411601- *fpsnumformat*: collects all utility functions related to **number formats**.
16421602
16431603All other units are probably not needed at the application level. In case of the **visual spreadsheet controls**, the needed units usually are inserted at design-time automatically.
16441604
16451605### Excel 5 example
16461606
16471607Note: 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)
16481608
16491609``` pascal
16501610{
16511611excel5demo.dpr
16521612
16531613Demonstrates how to write an Excel 5.x file using the fpspreadsheet library
16541614
16551615You can change the output format by changing the OUTPUT_FORMAT constant
16561616
16571617AUTHORS: Felipe Monteiro de Carvalho
16581618}
16591619program excel5demo;
16601620
16611621{$mode delphi}{$H+}
16621622
16631623uses
16641624 Classes, SysUtils, fpstypes, fpspreadsheet, fpsallformats, laz_fpspreadsheet;
16651625
16661626const
16671627 OUTPUT_FORMAT = sfExcel5;
16681628
16691629var
16701630 MyWorkbook: TsWorkbook;
16711631 MyWorksheet: TsWorksheet;
16721632 MyFormula: TsRPNFormula;
16731633 MyDir: string;
16741634begin
16751635 // Initialization
16761636 MyDir := ExtractFilePath(ParamStr(0));
16771637
16781638 // Create the spreadsheet
16791639 MyWorkbook := TsWorkbook.Create;
16801640 try
16811641 MyWorksheet := MyWorkbook.AddWorksheet('My Worksheet');
16821642
16831643 // Write some number cells
16841644 MyWorksheet.WriteNumber(0, 0, 1.0);
16851645 MyWorksheet.WriteNumber(0, 1, 2.0);
16861646 MyWorksheet.WriteNumber(0, 2, 3.0);
16871647 MyWorksheet.WriteNumber(0, 3, 4.0);
16881648
16891649 // Write the formula E1 = A1 + B1
16901650 MyWorksheet.WriteFormula(0, 4, 'A1+B1');
16911651
16921652 // Creates a new worksheet
16931653 MyWorksheet := MyWorkbook.AddWorksheet('My Worksheet 2');
16941654
16951655 // Write some string cells
16961656 MyWorksheet.WriteText(0, 0, 'First');
16971657 MyWorksheet.WriteText(0, 1, 'Second');
16981658 MyWorksheet.WriteText(0, 2, 'Third');
16991659 MyWorksheet.WriteText(0, 3, 'Fourth');
17001660
17011661 // Save the spreadsheet to a file
17021662 MyWorkbook.WriteToFile(MyDir + 'test' + STR_EXCEL_EXTENSION, OUTPUT_FORMAT);
17031663 finally
17041664 MyWorkbook.Free;
17051665 end;
17061666end.
17071667```
17081668
17091669### Opening an existing spreadsheet
17101670
17111671To open a spreadsheet while specifying a particular format to use use `ReadFromFile` with two parameters:
17121672
17131673``` pascal
17141674MyWorkbook.ReadFromFile(AFileName, sfExcel5);
17151675```
17161676
17171677It is also possible to call `ReadFromFile` with only one parameter, the filename. Then the workbook will use the extension to auto-detect the file format. In case of the ambiguous extension *.xls* (Excel 2-8) it will simply try various possibilities until one works. Although typical fingerprint byte patterns are checked now it is still possible that an exception will be raised for each incorrect format if run from the IDE at designtime; this does not occur at runtime.
17181678
17191679``` pascal
17201680MyWorkbook.ReadFromFile(AFileName);
17211681```
17221682
17231683### Writing a spreadsheet to file based on extension
17241684
17251685Similar to the `ReadFromFile` routine, there is also a `WriteToFile` procedure 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.
17261686
17271687As above, this code patches the *fpspreadsheet.pas* unit.
17281688
17291689``` pascal
17301690procedure TsWorkbook.WriteToFile(const AFileName: string; const AOverwriteExisting: Boolean = False); overload;
17311691var SheetType: TsSpreadsheetFormat;
17321692begin
17331693 if getFormatFromFileName(AFileName, SheetType) then
17341694 WriteToFile(AFileName, SheetType, AOverwriteExisting)
17351695 else raise Exception.Create(Format(
17361696 '[TsWorkbook.WriteToFile] Attempted to save a spreadsheet by extension, but the extension %s is invalid.', [ExtractFileExt(AFileName)]));
17371697end;
17381698```
17391699
17401700### Iterating through all Worksheets
17411701
17421702``` pascal
17431703var
17441704 MyWorkbook: TsWorkbook;
17451705 MyWorksheet: TsWorksheet;
17461706 i: Integer;
17471707begin
17481708 // Here load MyWorkbook from a file or build it
17491709
17501710 for i := 0 to MyWorkbook.GetWorksheetCount() - 1 do
17511711 begin
17521712 MyWorksheet := MyWorkbook.GetWorksheetByIndex(i);
17531713 // Do something with MyWorksheet
17541714 end;
17551715```
17561716
17571717### Iteration through cells
17581718
17591719The first idea is to use a simple **for-to** loop:
17601720
17611721``` pascal
17621722var
17631723 MyWorksheet: TsWorksheet;
17641724 col, row: Cardinal;
17651725 cell: PCell;
17661726begin
17671727 for row:=0 to MyWorksheet.GetLastRowIndex do
17681728 for col := 0 to MyWorksheet.GetLastColIndex do
17691729 begin
17701730 cell := MyWorksheet.FindCell(row, col);
17711731 WriteLn(MyWorksheet.ReadAsUTF8Text(cell));
17721732 end;
17731733end;
17741734```
17751735
17761736`FindCell` initiates a search for a cell independently of the previously found cell. Cells, however, are are organized interally in a sorted tree structure, and each cell "knows" its previous and next neighbors. Moreover, `FindCell` wastes time on searching for non-existing cells in case of sparsely-occupied worksheets. In general, it is more efficient to use the **for-in** syntax which takes advantage of the internal tree structure by means of special **enumerators**. Note that there are also dedicated enumerators for searching along rows, columns or in cell ranges:
17771737
17781738``` pascal
17791739var
17801740 MyWorksheet: TsWorksheet;
17811741 cell: PCell;
17821742begin
17831743 // Search in all cells
17841744 for cell in Myworksheet.Cells do
17851745 WriteLn(MyWorksheet.ReadAsText(cell));
17861746
17871747 // Search in column 0 only
17881748 for cell in MyWorksheet.Cells.GetColEnumerator(0) do
17891749 WriteLn(MyWorksheet.ReadAsText(cell));
17901750
17911751 // Search in row 2 only
17921752 for cell in MyWorksheet.Cells.GetRowEnumerator(2) do
17931753 WriteLn(MyWorksheet.ReadAsText(cell));
17941754
17951755 // Search in range A1:C2 only (rows 0..1, columns 0..2)
17961756 for cell in MyWorksheet.Cells.GetRangeEnumerator(0, 0, 1, 2) do
17971757 WriteLn(MyWorksheet.ReadAsText(cell));
17981758end;
17991759```
18001760
18011761### Converting a database to a spreadsheet
18021762
18031763The easiest solution is to use the DatasetExport component.
18041764
18051765If you need to have more control over the process, use something like:
18061766
18071767``` pascal
18081768program db5xls;
18091769
18101770{$mode delphi}{$H+}
18111771
18121772uses
18131773 Classes, SysUtils,
18141774 // add database units
18151775 fpstypes, fpspreadsheet, fpsallformats;
18161776
18171777const OUTPUT_FORMAT = sfExcel5;
18181778
18191779var
18201780 MyWorkbook: TsWorkbook;
18211781 MyWorksheet: TsWorksheet;
18221782 MyDatabase: TSdfDataset;
18231783 MyDir: string;
18241784 i, j: Integer;
18251785begin
18261786 // Initialization
18271787 MyDir := ExtractFilePath(ParamStr(0));
18281788
18291789 // Open the database
18301790 MyDatabase := TSdfDataset.Create;
18311791 MyDatabase.Filename := 'test.dat';
18321792 // Add table description here
18331793 MyDatabase.Active := True;
18341794
18351795 // Create the spreadsheet
18361796 MyWorkbook := TsWorkbook.Create;
18371797 MyWorksheet := MyWorkbook.AddWorksheet('My Worksheet');
18381798
18391799 // Write the field names
18401800 for i := 0 to MyDatabase.Fields.Count - 1 do
18411801 MyWorksheet.WriteText(0, i, MyDatabase.Fields[i].FieldName);
18421802
18431803 // Write all cells to the worksheet
18441804 MyDatabase.First;
18451805 j := 0;
18461806 while not MyDatabase.EOF do
18471807 begin
18481808 for i := 0 to MyDatabase.Fields.Count - 1 do
18491809 MyWorksheet.WriteText(j + 1, i, MyDatabase.Fields[i].AsString);
18501810
18511811 MyDatabase.Next;
18521812 Inc(j);
18531813 end;
18541814
18551815 // Close the database
18561816 MyDatabase.Active := False;
18571817 MyDatabase.Free;
18581818
18591819 // Save the spreadsheet to a file
18601820 MyWorkbook.WriteToFile(MyDir + 'test' + STR_EXCEL_EXTENSION, OUTPUT_FORMAT);
18611821 MyWorkbook.Free;
18621822end.
18631823```
18641824
18651825### Converting a large database table to a spreadsheet using virtual mode
18661826
18671827> **Note:** The example program in *examples\db_import_export* shows a demonstration of using virtual mode to export datasets to spreadsheet files.
18681828
18691829We want to write a large database table to a spreadsheet file. The first row of the spreadsheet is to show the field names in bold type face and with a gray background.
18701830
18711831Normally, FPSpreadsheet would load the entire representation of the spreadsheet into memory, so we'll use virtual mode to minimize memory usage.
18721832
18731833``` pascal
18741834type
18751835 TDataProvider = class;
18761836
18771837var
18781838 MyWorkbook: TsWorkbook;
18791839 MyWorksheet: TsWorksheet;
18801840 MyDatabase: TSdfDataset;
18811841 MyDir: string;
18821842 MyHeaderTemplateCell: PCell;
18831843 DataProvider: TDataProvider;
18841844
18851845// Implement TDataProvider here - see below...
18861846
18871847begin
18881848 // Initialization
18891849 MyDir := ExtractFilePath(ParamStr(0));
18901850
18911851 // Open the database
18921852 MyDatabase := TSdfDataset.Create;
18931853 try
18941854 MyDatabase.Filename := 'test.dat';
18951855 // Add table description here
18961856 MyDatabase.Active := True;
18971857
18981858 // Create the spreadsheet
18991859 MyWorkbook := TsWorkbook.Create;
19001860 try
19011861 MyWorksheet := MyWorkbook.AddWorksheet('My Worksheet');
19021862
19031863 // Create the template cell for the header line, we want the
19041864 // header in bold type-face and gray background color
19051865 // The template cell can be anywhere in the workbook, let's just select cell A1.
19061866 MyWorksheet.WriteFontStyle(0, 0, [fssBold]);
19071867 MyWorksheet.WriteBackgroundColor(0, 0, scGray);
19081868 // We'll need this cell again and again, so let's save the pointer to it in a variable
19091869 MyHeaderTemplateCell := MyWorksheet.Find(0, 0);
19101870
19111871 // Enter virtual mode
19121872 MyWorkbook.Options := MyWorkbook.Options + [boVirtualMode];
19131873
19141874 // Define number of columns - we want a column for each field
19151875 MyWorksheet.VirtualColCount := MyDatabase.FieldCount;
19161876
19171877 // Define number of rows - we want every record, plus 1 row for the title row
19181878 MyWorksheet.VirtualRowCount := MyDatabase.RecordCount + 1;
19191879
19201880 // Link the event handler which passes data from database to spreadsheet writer
19211881 MyWorksheet.OnWriteCellData := @DataProvider.WriteCellData;
19221882
19231883 // Write all cells to an Excel8 file
19241884 // The data to be written are specified in the OnWriteCellData event handler.
19251885 MyWorkbook.WriteToFile(MyDir + 'test.xls', sfExcel8);
19261886
19271887 finally
19281888 // Clean-up
19291889 MyWorkbook.Free;
19301890 end;
19311891
19321892 finally
19331893 // Close the database & clean-up
19341894 MyDatabase.Active := False;
19351895 MyDatabase.Free;
19361896 end;
19371897
19381898end.
19391899```
19401900
19411901What is left is to write the event handler for `OnWriteCellData`. For the command-line program above we setup a particular data provider class (in a gui program the event handler can also be a method of any form):
19421902
19431903``` pascal
19441904type
19451905 TDataProvider = class
19461906 procedure WriteCellData(Sender: TsWorksheet; ARow, ACol: Cardinal; var AValue: variant; var AStyleCell: PCell);
19471907 end;
19481908
19491909procedure TDataProvider.WriteCellData(Sender: TsWorksheet; ARow, ACol: Cardinal; AValue: variant; var: AStyleCell: PCell);
19501910begin
19511911 // Let's handle the header row first:
19521912 if ARow = 0 then begin
19531913 // The value to be written to the spreadsheet is the field name.
19541914 AValue := MyDatabase.Fields[ACol].FieldName;
19551915 // Formatting is defined in the HeaderTemplateCell.
19561916 AStyleCell := MyHeaderTemplateCell;
19571917 // Move to first record
19581918 MyDatabase.First;
19591919 end else begin
19601920 // The value to be written to the spreadsheet is the record value in the field corresponding to the column.
19611921 // No special requirements on formatting --> leave AStyleCell at its default (nil).
19621922 AValue := MyDatabase.Fields[ACol].AsVariant;
19631923 // Advance database cursor if last field of record has been written
19641924 if ACol = MyDatabase.FieldCount-1 then MyDatabase.Next;
19651925 end;
19661926end;
19671927```
19681928
19691929### Converting between two spreadsheet formats
19701930
19711931``` pascal
19721932program ods2xls;
19731933
19741934{$mode delphi}{$H+}
19751935
19761936uses
19771937 Classes, SysUtils,
19781938 fpstypes, fpspreadsheet, fpsallformats, fpspreadsheet_pkg;
19791939
19801940const
19811941 INPUT_FORMAT = sfOpenDocument;
19821942 OUTPUT_FORMAT = sfExcel8;
19831943
19841944var
19851945 MyWorkbook: TsWorkbook;
19861946 MyDir: string;
19871947begin
19881948 // Initialization
19891949 MyDir := ExtractFilePath(ParamStr(0));
19901950
19911951 // Convert the spreadsheet
19921952 MyWorkbook := TsWorkbook.Create;
19931953 try
19941954 MyWorkbook.ReadFromFile(MyDir + 'test.ods', INPUT_FORMAT);
19951955 MyWorkbook.WriteToFile(MyDir + 'test.xls', OUTPUT_FORMAT);
19961956 finally
19971957 MyWorkbook.Free;
19981958 end;
19991959end.
20001960```
20011961
20021962### Reading and writing of CSV files
20031963
20041964CSV files (CSV = comma-separated values) are plain text files without metadata. Therefore, additional information for correct reading of writing from/to a worksheet is required. The global record `CSVParams` makes available fundamental settings for this purpose:
20051965
20061966``` pascal
20071967type
20081968 CSVParams: TsCSVParams = record // W = writing, R = reading, RW = reading/writing
20091969 SheetIndex: Integer; // W: Index of the sheet to be written
20101970 LineEnding: TsCSVLineEnding; // W: Specification for line ending to be written
20111971 Delimiter: Char; // RW: Column delimiter
20121972 QuoteChar: Char; // RW: Character for quoting texts
20131973 Encoding: String; // RW: Encoding of file
20141974 DetectContentType: Boolean; // R: try to convert strings to content types
20151975 NumberFormat: String; // W: if empty write numbers like in sheet, otherwise use this format
20161976 AutoDetectNumberFormat: Boolean; // R: automatically detects decimal/thousand separator used in numbers
20171977 TrueText: String; // RW: String for boolean TRUE
20181978 FalseText: String; // RW: String for boolean FALSE
20191979 FormatSettings: TFormatSettings; // RW: add'l parameters for conversion
20201980 end;
20211981```
20221982
20231983This record contains fields which are evaluated for reading only, writing only, or for both - see the attached comments.
20241984
20251985A common situation is to read a file using a number decimal separator which is different from the system's decimal separator: Suppose you are on a European system in which the decimal separator is a comma, but the csv file to be read originates from a machine which uses a decimal point. And suppose also, that the file contains tab characters as column separator instead of the default comma. In this case, simply set the `CSVParams.FormatSettings.DecimalSeparator` to `'.'`, and the `CSVParams.Delimiter` to `#9` (TAB character) before reading the file:
20261986
20271987``` pascal
20281988uses
20291989 fpstypes, fpspreadsheet, fpscsv;
20301990var
20311991 MyWorkbook: TsWorkbook;
20321992begin
20331993 CSVParams.FormatSettings.DecimalSeparator := '.';
20341994 CSVParams.Delimiter := #9;
20351995 MyWorkbook := TsWorkbook.Create;
20361996 try
20371997 MyWorkbook.ReadFromFile('machine-data.csv', sfCSV);
20381998 finally
20391999 MyWorkbook.Free;
20402000 end;
20412001end;
20422002```
20432003
20442004> **Note:** If you want to give the user the possibility to interactively modify the `CSVParams` record have a look at the unit *scsvparamsform.pas* of the *spready* demo which provides a ready-to-use dialog.
20452005
20462006### Sample projects in the fpspreadsheet installation folder
20472007
20482008A bunch of sample projects accompanies the FPSpreadsheet installation. They can be found in the folder "examples". Here is a brief description of these sample projects
20492009
20502010- **db_import_export** is an example showing how to export a large database table to a spreadsheet file using virtual mode or **TFPSExport**. It also shows importing the spreadsheet into a database using virtual mode.
20512011- **fpsspeedtest** compares the effect of file format and various reading/writing parameters on the speed of writing and reading very large spreadsheet files. Again, please run the write test first which create the test files used for the read test.
20522012- Folder **read_write**:
20532013 - **excel2demo** contains command-line programs for writing and reading Excel 2.x xls files. Please run the write demo before the read demo so the required spreadsheet file is generated.
20542014 - **excel5demo**, like excel2demo, but for Excel 5 xls files.
20552015 - **excel8demo**, like excel2demo, but for Excel 97-2003 xls files.
20562016 - **csvdemo**, like excel2demo, but for CSV files.
20572017 - **htmldemo**, like excel2demo, but for HTML file (currently writing only).
20582018 - **ooxmldemo**, like excel2demo, but for the new Excel xlsx files.
20592019 - **opendocdemo**, like excel2demo, but for OpenOffice/LibreOffice ods files
20602020 - **wikitabledemo**, like excel2demo, but for wiki table files. Note that the write example currently writes a format that the read example cannot understand.
20612021- **other**: simple commandline programs showing various aspects of the fpspreadsheet package. Have a look at *readme.txt* for more details.
20622022- Folder **visual**:
20632023 - **fpschart** shows the application of the [[TsWorksheetChartSource]] and TsWorkbookChartSource and the interaction with the [[TAChart]] plotting package.
20642024 - **fpsctrls** and **visual/fpsctrls_no_install** create a GUI spreadsheet application with a minimum amount of written code; the latter demo is good for testing because it does not require installation of the FPSpreadsheet packages. Step-by-step instructions on how *fpsctrls* is made can be found in the [[FPSpreadsheet tutorial: Writing a mini spreadsheet application|FSpreadsheet tutorial]].
20652025 - **fpsgrid** and **visual/fpsgrid_no_install** show the basic application of the [[TsWorksheetGrid]] without using the TsWorkbookSource component; the latter demo does not require installation of any FPSpreadsheet package.
20662026 - **spready**: an extended application of the [[TsWorksheetGrid]] showing spreadsheet files with formatting, editing of cells, etc. Note that this demo can be simplified by taking advantage of the FPSpreadsheet controls.
20672027- **wikitablemaker** is a small application for creation of code to be used for tables on wiki pages. Type the data into a [[TsWorksheetGrid]] (or load an existing spreadsheet file), go to page "Code" to see the generated wiki code, click "Copy to clipboard" and paste the code into the wiki page.
20682028
20692029## Download
20702030
20712031### Subversion
20722032
20732033You can download FPSpreadsheet using the subversion software and the following command line:
20742034
20752035``` bash
20762036svn checkout svn://svn.code.sf.net/p/lazarus-ccr/svn/components/fpspreadsheet fpspreadsheet
20772037```
20782038
20792039#### SVN change log
20802040
20812041- **"Rich-text" formatting** of label cells, i.e. assignment different fonts to groups of characters within the cell text. For this purpose, HTML codes (such as `<B>...</B>`) can be embedded in the cell text to identify the parts with different font (--\> `TsWorksheet.WriteTextAsHTML`).
20822042- **Searching** for cells with specified content in worksheet or workbook.
20832043- Support for reading and writing of **HTML format**
20842044- Support for writing of the **ExcelXML format** (Excel XP and 2003)
20852045- Ability to use **user-provided file reader/writer classes** to extend FPSpreadsheet to new file formats.
20862046- Readers and writers now support all the **line styles** of Excel8 and OOXML.
20872047- xls, xlsx and ods readers/writers now support the **active worksheet** and **selected cell**.
20882048- Ability to write to/read from the system's **clipboard** for copy & paste using the visual controls.
20892049- Support for **print ranges** and **repeated header rows and columns** in the Office applications.
20902050- Support for **embedded images** (currently only writing to xlsx and ods, no reading).
20912051- Improved compatibility of **TsWorksheetGrid** with TStringGrid (`Cells[Col,Row]` property). Standalone application as an advanced StringGrid replacement.
20922052- Support for **Right-to-left mode** in TsWorksheetGrid. In addition to the system-wide RTL mode, there are also parameters `BiDiMode` in the Worksheet and cells allowing to controls text direction at worksheet and cell level individually, like in Excel or LibreOffice Calc.
20932053- Support of several **units** for specification of column widths and row heights.
20942054- The library now supports **localization** using po files. Translations are welcome.
20952055
20962056#### Incompatible changes
20972057
20982058- VirtualMode was changed in order to be able to treat worksheets of the same workbook differently. `VirtualRowCount` and `VirtualColCount` are now properties of the worksheet, and similarly, the event handler `OnWriteCellData`. In older versions, these properties had belonged to the workbook.
20992059- The worksheet methods `ReadAsUTF8Text` and `WriteUTF8Text` have been renamed to `ReadAsText` and `WriteText`, respectively. The old ones are still available and marked as deprecated; they will be removed in later versions.
21002060- The public properties of `TsWorksheetGrid` using a `TRect` as parameter were modified to use the Left, Top, Right, Bottom values separately.
21012061- The `PageLayout` is a class now, no longer a record. As a consequence, some array properties cannot be set directly any more, use the corresponding methods instead.
21022062- Most of the predefined color constants were marked as deprecated; only the basic EGA colors will remain.
21032063
21042064#### To do list
21052065
21062066Note: 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!
21072067
21082068- Find out why BIFF2 files are corrupt when saved with frozen rows/cols activated.
21092069- Find out how to write more than 21 number formats to a BIFF2 file (Office 97 can do this).
21102070- Add row and column formats
21112071- Add reading support for wikitable (Mediawiki) files
21122072- xls reader crashes for some incorrectly written xls files (which Excel can read), see [<http://forum.lazarus.freepascal.org/index.php/topic,25624.0.html>](http://forum.lazarus.freepascal.org/index.php/topic,25624.0.html).
21132073- Improve color support: due to palette support colors may change from file to file currently.
21142074- Add embedded images.
21152075- Fix writing of cell comments to BIFF8 files.
21162076
21172077**Long-term:**
21182078
21192079- 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.
21202080- Store formatting in a format list of the workbook, not in the cell, to reduce memory usage.
21212081- Use BIFF8 file-wide string storage instead of storing strings in cells (should reduce memory usage in case of many duplicate strings)
21222082- Redo ooxml and ods readers based upon SAX/TXmlReader instead of DOM to reduce memory usage of large files.
21232083- Add an fpspreadsheetexport unit and component on "Data Export" tab similar to [[fpdbfexport]] FPSpreadsheetexport demo preferably with all export formats component. Find a way to register export format to all formats (look into how lazreport pdf export performs a similar procedure).
21242084
21252085### Stable releases
21262086
21272087You can find all releases of FPSpreadsheet on [sourceforge](https://sourceforge.net/projects/lazarus-ccr/files/FPSpreadsheet/).
21282088
21292089#### Version 1.6
21302090
21312091The latest stable release is version 1.6.2.
21322092
21332093##### Change log (with respect to v1.4.x)
21342094
21352095- TsWorkbookChartSource is a new component which facilitates creation of charts from non-contiguous spreadsheet data in various worksheets. It interfaces to a workbook via tha WorkbookSource component. In the long run, it will replace the older TsWorksheetChartSource which required contiguous x/y data blocks in the same worksheet.
21362096- Major reconstruction of the cell record resulting in strong reduction of memory consumption per cell (from about 160 bytes per cell down to about 50)
21372097- Implementation of a record helper for the TCell which simplifies cell formatting (no need to set a bit in UsedFormattingFields any more, automatic notification of visual controls)
21382098- Comments in cells
21392099- Background fill patterns
21402100- Hyperlinks
21412101- Enumerators for worksheet's internal AVLTrees for faster iteration using a for-in loop.
21422102- Formatting of numbers as fractions.
21432103- Improved number format parser for better recognition of Excel-like number formats.
21442104- Page layout (page margins, headers, footer, used for only when printing in the Office applications - no direct print support in fpspreadsheet!)
21452105- Improved color management: no more palettes, but direct rgb colors. More pre-defined colors.
21462106- A snapshot of the wiki documentation is added to the library as chm help file.
21472107
21482108##### Incompatible changes
21492109
21502110- All type declarations and constants are moved from fpspreadsheet.pas to the new unit **fpstypes.pas**. Therefore, most probably, this unit has to be added to the uses clause.
21512111- Because fpspreadsheet supports now **background** fill patterns the cell property `BackgroundColor` has been replaced by `Background`. Similarly, the `UsedFormattingFields` flag `uffBackgroundColor` is called `uffBackground` now.
21522112- Another `UsedFormattingFields` flag has been dropped: **`uffBold`**. It is from the early days of fpspreadsheet and has become obsolete since the introduction of full font support. For achieving a bold type-face, now call `MyWorksheet.WriteFont(row, col, BOLD_FONTINDEX)`, or `Myworksheet.WriteFontStyle(row, col, [fssBold])`.
21532113- **Iteration through cells** using the worksheet methods `GetFirstCell` and `GetNextCell` has been removed - it failed if another iteration of this kind was called within the loop. Use the new for-in syntax instead.
21542114- Support for **shared formulas** has been reduced. The field `SharedFormulaBase` has been deleted from the TCell record, and methods related to shared formulas have been removed from TsWorksheet. Files containing shared formulas can still be read, the shared formulas are converted to multiple normal formulas.
21552115- The **color palettes** of previous versions have been abandoned. `TsColor` is now a `DWord` representing the rgb components of a color (just like TColor does in the *graphics* unit), it is not an index into a color palette any more. The values of pre-defined colors, therefore, have changed, their names, however, are still existing. The workbook functions for palette access have become obsolete and were removed.
21562116
21572117#### Version 1.4
21582118
21592119##### Change log (with respect to v1.2.x)
21602120
21612121- Full support for **string formulas**; calculation of RPN and string formulas for all built-in formulas either directly or by means of registration mechanism. Calculation occurs when a workbook is saved (activate workbook option `boCalcBeforeSaving`) or when cell content changes (active workbook option `boAutoCalc`).
21622122- **Shared formulas** (reading for sfExcel5, sfExcel8, sfOOXML; writing for sfExcel2, sfExcel5, sfExcel8).
21632123- Significant **speed-up** of writing of large spreadsheets for the xml-based formats (ods and xlsx), speed up for biff2; **speedtest demo** program
21642124- **VirtualMode** allowing to read and write very large spreadsheet files without loading entire document representation into memory. Formatting of cells in VirtualMode.
21652125- Demo program for database export using virtual mode and TFPSExport.
21662126- Added db export unit allowing programmatic exporting datasets using **TFPSExport**. Similar export units are e.g. [[fpdbfexport]], [[fpXMLXSDExport]].
21672127- Reader for **xlsx** files, now fully supporting the same features as the other readers.
21682128- Reader/writer for **CSV files** based on [[CsvDocument]].
21692129- **Wikitables writer** supports now most of the fpspreadsheet formatting options (background color, font style, font color, text alignment, cell borders/line styles/line colors, merged cells, column widths, row heights); new "wikitablemaker" demo
21702130- **Insertion and deletion of rows and columns** into a worksheet containing data.
21712131- Implementation of **sorting** of a worksheet.
21722132- Support of **diagonal "border" lines**
21732133- **Logging of non-fatal error messages** during reading/writing (TsWorksheet.ErrorMsg)
21742134- **Merged** cells
21752135- **Registration** of currency strings for automatic conversion of strings to **currency values**
21762136- A set of **visual controls** (TsWorkbookSource, TsWorkbookTabControl, TsSpreadsheetInspector, TsCellEdit, TsCellIndicator, TsCellCombobox, in addition to the already-existing TsWorksheetGrid) and pre-defined standard actions to facilitate [[FPSpreadsheet tutorial: Writing a mini spreadsheet application|creation of GUI applications]].
21772137- **Overflow cells** in TsWorksheetGrid: label cells with text longer than the cell width extend into the neighboring cell(s).
21782138
21792139##### Incompatible changes
21802140
21812141- The option `soCalcBeforeSaving` now belongs to the workbook, no longer to the worksheet, and has been renamed to `boCalcBeforeSaving` (it controls automatic calculation of formulas when a workbook is saved).
21822142- The workbook property `ReadFormulas` is replaced by the option flag `boReadFormulas`. This means that you have to add this flag to the workbook's `Options` in order to activate reading of formulas.
21832143- With full support of string formulas some features related to RPN formulas were removed:
21842144 - The field `RPNFormulaResult` of TCell was dropped, as well as the element `cctRPNFormula` in the `TsContentType` set.
21852145 - Sheet function identifiers were removed from the `TsFormulaElement` set, which was truncated after `fekParen`.
21862146 - To identify a sheet function, its name must be passed to the function `RPNFunc` (instead of using the now removed `fekXXXX` token). In the array notation of the RPN formula, a sheet function is identified by the new token `fekFunc`.
21872147 - The calling convention for registering user-defined functions was modified. It now also requires the Excel ID of the function (see "OpenOffice Documentation of Microsoft Excel Files", section 3.11, or unit *xlsconst* containing all token up to ID 200 and some above).
21882148 - Code related to RPN formulas was moved to a separate unit, `fpsRPN`. Add this unit to the uses clause if you need RPN features.
21892149
21902150#### Wiki documentation of old releases
21912151
21922152This wiki page is work in progress and updated whenever a new feature is added; therefore, its state corresponds to the svn trunk version of the package. If you work with an older stable version please use these "historic" wiki versions:
21932153
21942154- Version 1.4: [wiki.lazarus.freepascal.org/index.php?title=FPSpreadsheet&oldid=85299](http://wiki.lazarus.freepascal.org/index.php?title=FPSpreadsheet&oldid=85299)
21952155- Version 1.2 and 1.2.1: [wiki.lazarus.freepascal.org/index.php?title=FPSpreadsheet&oldid=81375](http://wiki.lazarus.freepascal.org/index.php?title=FPSpreadsheet&oldid=81375)
21962156
21972157## Instalación
21982158
21992159- Si únicamente necesitas componentes no gráficos: en Lazarus: Paquete -\> Abrir Archivo de Paquete (.lpk)...-\> Seleccionar **laz_fpspreadsheet.lpk** y hacer Click en \[**Compilar**\]. Con esto ahora el paquete es reconocible por Lazarus (y debería por ejemplo mostrarse en Paquetes/Enlaces de Paquete. Ya se puede añadir por tanto una dependencia en `laz_fpspreadsheet` dentro de tus opciones de proyecto y `fpspreadsheet` a la claúsula **uses** de las units del proyecto en las que se necesita utilizar.
22002160- If you also want GUI components ([[TsWorksheetGrid]] and [[TsWorksheetChartSource]]): 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.
22012161- If you want to have a GUI component for dataset export: Package/Open Package File, select **laz_fpspreadsheetexport_visual.lpk**, click Compile, then click, Use, Install and follow the prompts to rebuild Lazarus with the new package. Drop needed export components from the **Data Export** tab on your forms as usual.
22022162- FPSpreadsheet is developed with the latest stable fpc version (currently fpc 2.6.4). We only occasionally check older versions.
22032163- The basic spreadsheet functionality works with Lazarus versions back to version 1.0. Some visual controls or demo programs, however, require newer versions. Please update your Lazarus if you have an older version and experience problems.
22042164
22052165### Compiler options
22062166
22072167Here is a list of **conditional defines** which can be activated in order to tweak some operating modes of the packages and/or make it compilable with older Lazarus/FPC versions:
22082168
22092169- `FPS_DONT_USE_CLOCALE`: In Unix systems, the unit `clocale` is automatically added to the uses clause of *fpspreadsheet.pas*. This unit sets up localization settings needed for locale-dependent number and date/time formats. However, this adds a dependence on the C library to the package [1](http://lazarus-ccr.sourceforge.net/docs/rtl/clocale/index.html). If this is not wanted, define `FPS_DONT_USE_CLOCALE`.
22102170- `FPS_VARISBOOL`: fpspreadsheet requires the function VarIsBool which was introduced by fpc 2.6.4. If an older FPC versions is used define `FPS_VARISBOOL`. Keep undefined for the current FPC version.
22112171- `FPS_LAZUTF8`: fpspreadsheet requires some functions from the unit LazUTF8 which were introduced by Lazarus 1.2. If an older Lazarus version is used define `FPS_LAZUTF8`. Keep undefined for the current Lazarus version.
22122172
22132173All these defines are collected in the include file *fps.inc*.
22142174
22152175## Soporte y reporte de errores
22162176
22172177El lugar reconmendado para discusión y soporte sobre FPSpreadsheet es consultado en el [foro de Lazarus](http://forum.lazarus.freepascal.org/index.php?board=49.0).
22182178
22192179Los reportes de error deben enviarse a [Seguimiento de errores de Lazarus/Free Pascal](http://bugs.freepascal.org/); por favor, especificar el proyecto "Lazarus-CCR".
22202180
22212181## Current Progress
22222182
22232183### Progress by supported cell content
22242184
2225-<thead>
2226-
2227-sheets</th>
2228-
2229-support</th>
2230-
2231-support</th>
2232-
2233-Formula</th>
2234-
2235-Formula</th>
2236-
2237-</thead>
2238-<tbody>
2239-
2240-</tbody>
2185+| Format | Multiple · sheets | Unicode | Reader · support | Writer · support | Text | Number | String · Formula | RPN · Formula | Date/Time | Comments | Hyperlinks | Images +++ |
2186+|---|---|---|---|---|---|---|---|---|---|---|---|---|
2187+| CSV files | No | Yes + | Working ++ | Working ++ | Working ++ | Working ++ | N/A | N/A | Working ++ | N/A | N/A | N/A |
2188+| Excel 2.x | No | No * | Working ** | Working | Working | Working | Working | Working *** | Working | Working | N/A | N/A |
2189+| Excel 5.0 (Excel 5.0 and 95) | Yes | No * | Working ** | Working | Working | Working | Working | Working *** | Working | Working | N/A | N/A |
2190+| Excel 8.0 (Excel 97- 2003) | Yes | Yes | Working ** | Working | Working | Working | Working | Working *** | Working | Reading only | Working | Not working |
2191+| Microsoft OOXML | Yes | Yes | Working ** | Working | Working | Working | Working *** | Working | Working | Working | Working | Writing only |
2192+| OpenDocument | Yes | Yes | Working ** | Working | Working | Working | Working *** | Working | Working | Working | Working | Working |
2193+| HTML | No | Yes | Working ++ | Working ++ | Working ++ | Working ++ | N/A | N/A | Working ++ | N/A | Working | Not working |
2194+| Wikitable files (Mediawiki) | No | Yes | planned | Working ++ | Working ++ | Working ++ | N/A | N/A | Working ++ | N/A | N/A | Not working |
22412195
22422196(+) Depends on file.\
22432197(++) No "true" number format support because the file does not containg number formatting information. But the number format currently used in the spreadsheet understood.\
22442198(+++) Only very basic image support: no transformations, no cropping, no image manipulation.\
22452199(*) 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.\
22462200(**) Some cell could be returned blank due to missing or non ready implemented number and text formats.\
22472201(***) This is the format in which the formulas are written to file (determined by design of the file format).\
22482202(****) Writing of all formats is supported. Some rare custom formats, however, may not be recognized correctly. BIFF2 supports only built-in formats by design.
22492203
22502204### Progreso de las opciones de formateado
22512205
22522206Quite some formatting options are available:
22532207
2254-<thead>
2255-
2256-de texto</th>
2257-
2258-de texto</th>
2259-
2260-enriquecido</th>
2261-
2262-de color</th>
2263-
2264-wrap</th>
2265-
2266-Col&amp;Row</th>
2267-
2268-numeros</th>
2269-
2270-celdas</th>
2271-
2272-página</th>
2273-
2274-rangos</th>
2275-
2276-images</th>
2277-
2278-</thead>
2279-<tbody>
2280-
2281-</tbody>
2208+| Formato | Alineación · de texto | Rotación · de texto | Font | Texto · enriquecido | Borde | Soporte · de color | Fondo | Word · wrap | Tamaño · Col&Row | Formato · numeros | Unir · celdas | Distribución · página | Imprimirt · rangos | Encabezado/pie página · images |
2209+|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
2210+| CSV files | N/A | N/A | N/A | N/A | N/A | N/A | N/A | N/A | N/A | N/A | N/A | N/A | N/A | N/A |
2211+| Excel 2.x | Funciona * | N/A | Funciona | N/A | Funciona | Funciona | Funciona** | N/A | Funciona | Funciona | N/A | Funciona | N/A | N/A |
2212+| Excel 5.0 (Excel 5.0 and 95) | Funciona | Funciona | Funciona | Funciona | Funciona | Funciona | Funciona | Funciona | Funciona | Funciona | N/A | Funciona | Funciona | N/A |
2213+| Excel 8.0 (Excel 97 - XP) | Funciona | Funciona | Funciona | Funciona | Funciona | Funciona | Funciona | Funciona | Funciona | Funciona | Funciona | Funciona | Funciona | No funciona |
2214+| Microsoft OOXML (xlsx) | Funciona | Funciona | Funciona | Funciona | Funciona | Funciona | Funciona | Funciona | Funciona | Funciona | Funciona | Funciona | Funciona | Writing only |
2215+| OpenDocument | Funciona | Funciona | Funciona | Funciona | Funciona | Funciona | Funciona*** | Funciona | Funciona | Funciona | Funciona | Funciona | Funciona | Funciona |
2216+| HTML | Funciona | Errores | Funciona | Funciona | Errores | Funciona | Funciona | Writing only | Writing only | N/A | Funciona | N/A | N/A | No funciona |
2217+| Wikitable (Mediawiki) | Funciona | N/A | Funciona | No funciona | Funciona | Funciona | | Funciona | Funciona | N/A | Funciona | N/A | N/A | No funciona |
22822218
22832219(N/A) Característica no disponible intrínsecamente para este formato.\
22842220(*) BIFF2 soporta solamente alineación horizontal de texto, la alineación vertical se ignora.\
22852221(**) BIFF2 no soporta color de fondo; en su lugar se utiliza un fondo punteado en blanco y negro.\
22862222(***) OpenDocument soporta únicamente fondos uniformes; en su lugar se escribe un color de relleno interpolado entre foreground y background.\
22872223(****) Únicamente color de fondo uniforme, sin estilos de relleno.
22882224
22892225### Progreso del las opciones del interface de usuario para workbook/worksheet
22902226
22912227Se han añadido algunas opciones al interface de contenidos de fichero de `TsWorksheetGrid`:
22922228
22932229| Formato | Ocultar líneas de la grid | Ocultar cabeceras | Inmovilizar paneles | sheet/cell activa | Modo BiDi |
22942230|----|----|----|----|----|----|
22952231| Excel 2.x | Funciona | Funciona | No Funciona | N/A | N/A |
22962232| Excel 5.0 (Excel 5.0 and 95) | Funciona | Funciona | Funciona | Funciona | N/A |
22972233| Excel 8.0 (Excel 97 - XP) | Funciona | Funciona | Funciona | Funciona | Funciona |
22982234| Microsoft OOXML | Funciona | Funciona | Funciona | Funciona | Funciona |
22992235| OpenDocument | Funciona | Funciona | Funciona | Funciona | Funciona |
23002236| HTML | Solo escritura | Solo escritura | N/A | N/A | No Funciona |
23012237
23022238## Log de cambios
23032239
23042240Changes in the development version that have not yet been released are already documented on this page.
23052241
23062242- 13 April 2016:\
23072243 **Version 1.6.2** released, basado en svn revision 4619. Corrige el desbordamiento de enteros en las fórmulas ([Issue \#29999](https://bugs.freepascal.org/view.php?id=29999)).
23082244- 28 June 2015:\
23092245 **Version 1.6** released, based on svn release 4106. Consumo de memoria mejorado, comentarios, hiperenlaces, patrones de relleno de fondo, enumerador de celda, fraction number format, page layout, modified color management, versión fuera de línea de la wiki.
23102246- 13 March 2015:\
23112247 **Version 1.4.3** released. Corrige el cálculo de fórmula en una grid del worksheet.
23122248- 31 January 2015:\
23132249 **Version 1.4.2** released. Corrige la lectura incompleta de ficheros ods con celdas repetidas ([Issue \#0027389](https://bugs.freepascal.org/view.php?id=0027389))
23142250- 26 January 2015:\
23152251 **Version 1.4.1** released. A bugfix release para 1.4 que corrige el streaming incorrecto de TsWorksheetGrid y los errores de lectura para lectores biff5 y biff8.
23162252- 31 December 2014:\
23172253 **Version 1.4** released (based on subversion revision 3856 with full formula support, lector de xlsx, lectura y escritura de csv, wikitables writer, speed enhancement, virtual mode, db export component, row and column insertion/deletion, ordenación, fusión de celdas, controles visuales en adición a la grid de (mejorado) fpspreadsheet.
23182254- 3 September 2014:\
23192255 **Version 1.2.1** released. This is a bugfix release for 1.2 that fixes a bug in spreadsheetGrid ([Issue \#26521](https://bugs.freepascal.org/view.php?id=26521))
23202256- 26 June 2014:\
23212257 **Version 1.2** released (based on subversion revision 3241) with fpsgrid improvements, soporte en la celda para fecha/hora para .xls, .ods, vasta mejora en el soporte de formateado de celda, soporte mejorado de fórmulas, tests de la unit.
23222258- Jan 2013:\
23232259 **Version 1.1** released with all improvements up to revision 2621
23242260- Nov 2011:\
23252261 Released **version 1.0**, which includes OO XML generation support with bold formatting supported and also a lot of improvements from the last years
23262262- Jan 2009:\
23272263 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
23282264- Feb 2008:\
23292265 **Initial commit** to lazarus-ccr con soporte de escritura para Excel 2.1, Excel 5.0 (Windows solamente) y experimental para OOXML y OpenDocument.
23302266
23312267## Licencia
23322268
23332269LGPL with static linking exception. Es el mismo tipo de licecia que el utilizado por la librería de componentes de Lazarus.
23342270
23352271## Referencias
23362272
23372273### Enlaces Wiki
23382274
23392275- [[Office Automation]]
23402276- [[CsvDocument]]
23412277- [[RPN Formulas in FPSpreadsheet|RPN formulas in FPSpreadsheet]]
23422278- [[FPSpreadsheet: List of formulas]]
23432279- [[FPSpreadsheet tutorial: Writing a mini spreadsheet application]]
23442280
23452281### Enlaces externos
23462282
23472283- [Microsoft OLE Document Format](http://sc.openoffice.org/compdocfileformat.pdf)
23482284
23492285- [Excel file format description](http://sc.openoffice.org/excelfileformat.pdf)
23502286
23512287- 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/>](http://cgit.freedesktop.org/libreoffice/contrib/mso-dumper/). A similar application is the "BIFFExplorer" which can be found in the *applications* folder of ccr.
23522288
23532289- Iconos utilizados en los programas de demostración:
23542290
23552291- - [silk icons](http://www.famfamfam.com/lab/icons/silk/)
23562292 - [fugue icons](http://p.yusukekamiyamane.com/)
23572293
23582294---
23592295*From the Free Pascal wiki, page "FPSpreadsheet/es", as it stood on 2021-01-27 after a change by Slawek, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*

Back to history