From 9607fc8e8894987e7d354e96f84d097fecb7cbad Mon Sep 17 00:00:00 2001 From: wp_xxyyzz Date: Mon, 14 Jul 2014 15:04:04 +0000 Subject: [PATCH] fpspreadsheet: Extend the event OnNeedCellData by a template cell which can be used for formatting when saving a file in virtual mode. git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@3317 8e941d3f-bd1b-0410-a28a-d453659cc2b4 --- .../examples/other/test_virtualmode.lpr | 53 ++++++++++++------- components/fpspreadsheet/fpspreadsheet.pas | 2 +- components/fpspreadsheet/xlscommon.pas | 5 +- components/fpspreadsheet/xlsxooxml.pas | 6 ++- 4 files changed, 45 insertions(+), 21 deletions(-) diff --git a/components/fpspreadsheet/examples/other/test_virtualmode.lpr b/components/fpspreadsheet/examples/other/test_virtualmode.lpr index 6d2794157..641790f8d 100644 --- a/components/fpspreadsheet/examples/other/test_virtualmode.lpr +++ b/components/fpspreadsheet/examples/other/test_virtualmode.lpr @@ -12,11 +12,18 @@ uses type TDataProvider = class - procedure NeedCellData(Sender: TObject; ARow,ACol: Cardinal; var AData: variant); + procedure NeedCellData(Sender: TObject; ARow,ACol: Cardinal; + var AData: variant; var AStyleCell: PCell); end; +var + workbook: TsWorkbook; + worksheet: TsWorksheet; + dataprovider: TDataProvider; + headerTemplate: PCell; + procedure TDataProvider.NeedCellData(Sender: TObject; ARow, ACol: Cardinal; - var AData: variant); + var AData: variant; var AStyleCell: PCell); { This is just a sample using random data. Normally, in case of a database, you would read a record and return its field values, such as: @@ -28,6 +35,13 @@ type s: String; n: Double; begin + if ARow = 0 then begin + AData := Format('Column %d', [ACol + 1]); + AStyleCell := headerTemplate; + // This makes the style of the "headerTemplate" cell available to + // formatting of all virtual cells in row 0. + // Important: The template cell must be an existing cell in the worksheet. + end else if odd(random(10)) then begin s := Format('R=%d-C=%d', [ARow, ACol]); AData := s; @@ -40,11 +54,6 @@ type WriteLn('Writing row ', ARow, '...'); end; -var - workbook: TsWorkbook; - worksheet: TsWorksheet; - dataprovider: TDataProvider; - begin dataprovider := TDataProvider.Create; @@ -58,24 +67,32 @@ begin // workbook.WritingOptions := [woVirtualMode, woSaveMemory]; workbook.WritingOptions := [woVirtualMode]; + { woSaveMemory can be omitted, but is essential for large files: it causes + writing temporaray data to a file stream instead of a memory stream. + woSaveMemory, however, considerably slows down writing of biff files. } - // woSaveMemory can be omitted, but is essential for large files: it causes - // writing temporaray data to a file stream instead of a memory stream. - // woSaveMemory, however, considerably slows down writing of biff files. - + { Next two numbers define the size of virtual spreadsheet. + In case of a database, VirtualRowCount is the RecordCount, VirtualColCount + the number of fields to be written to the spreadsheet file } workbook.VirtualRowCount := 10000; workbook.VirtualColCount := 100; - // These two numbers define the size of virtual spreadsheet. - // In case of a database, VirtualRowCount is the RecordCount, VirtualColCount - // the number of fields to be written to the spreadsheet file + { The event handler for OnNeedCellData links the workbook to the method + from which it gets the data to be written. } workbook.OnNeedCellData := @dataprovider.NeedCellData; - // This links the worksheet to the method from which it gets the - // data to write. - // In case of a database, you would open the dataset before calling this: + { If we want to change the format of some cells we have to provide this + format in template cells of the worksheet. In the example, the first + row whould be in bold letters and have a gray background. + Therefore, we define a "header template cell" and pass this in the + NeedCellData event handler.} + worksheet.WriteFontStyle(0, 0, [fssBold]); + worksheet.WriteBackgroundColor(0, 0, scSilver); + headerTemplate := worksheet.FindCell(0, 0); + + { In case of a database, you would open the dataset before calling this: } workbook.WriteToFile('test_virtual.xlsx', sfOOXML, true); -// workbook.WriteToFile('test_virtual.xls', sfExcel5, true); +// workbook.WriteToFile('test_virtual.xls', sfExcel8, true); finally workbook.Free; diff --git a/components/fpspreadsheet/fpspreadsheet.pas b/components/fpspreadsheet/fpspreadsheet.pas index e33d8db59..2721c5665 100755 --- a/components/fpspreadsheet/fpspreadsheet.pas +++ b/components/fpspreadsheet/fpspreadsheet.pas @@ -714,7 +714,7 @@ type TsWorkbookWritingOptions = set of TsWorkbookWritingOption; TsWorkbookNeedCellDataEvent = procedure(Sender: TObject; ARow, ACol: Cardinal; - var AValue: variant) of object; + var AValue: variant; var AStyleCell: PCell) of object; {@@ The workbook contains the worksheets and provides methods for reading from diff --git a/components/fpspreadsheet/xlscommon.pas b/components/fpspreadsheet/xlscommon.pas index 96d5bdbe0..ecf69c262 100644 --- a/components/fpspreadsheet/xlscommon.pas +++ b/components/fpspreadsheet/xlscommon.pas @@ -2533,12 +2533,15 @@ var r,c: Cardinal; lCell: TCell; value: variant; + styleCell: PCell; begin for r := 0 to Workbook.VirtualRowCount-1 do begin for c := 0 to Workbook.VirtualColCount-1 do begin FillChar(lCell, SizeOf(lCell), 0); value := varNull; - Workbook.OnNeedCellData(Workbook, r, c, value); + styleCell := nil; + Workbook.OnNeedCellData(Workbook, r, c, value, styleCell); + if styleCell <> nil then lCell := styleCell^; lCell.Row := r; lCell.Col := c; if VarIsNull(value) then diff --git a/components/fpspreadsheet/xlsxooxml.pas b/components/fpspreadsheet/xlsxooxml.pas index 89769af29..eafa8590d 100755 --- a/components/fpspreadsheet/xlsxooxml.pas +++ b/components/fpspreadsheet/xlsxooxml.pas @@ -743,6 +743,7 @@ var AVLNode: TAVLTreeNode; CellPosText: string; value: Variant; + styleCell: PCell; fn: String; begin FCurSheetNum := Length(FSSheets); @@ -779,7 +780,10 @@ begin FillChar(lCell, SizeOf(lCell), 0); CellPosText := CurSheet.CellPosToText(r, c); value := varNull; - Workbook.OnNeedCellData(Workbook, r, c, value); + styleCell := nil; + Workbook.OnNeedCellData(Workbook, r, c, value, styleCell); + if styleCell <> nil then + lCell := styleCell^; lCell.Row := r; lCell.Col := c; if VarIsNull(value) then