fpspreadsheet: Complete database import demo. Rename dbexport to db_export_import. Fix biff2 crashing in ReadPane because of duplicate variable FWorksheet.

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@3434 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz 2014-08-06 08:50:36 +00:00
parent 8409952071
commit ebf59489f2
7 changed files with 201 additions and 113 deletions

View File

@ -6,7 +6,7 @@
<General> <General>
<SessionStorage Value="InProjectDir"/> <SessionStorage Value="InProjectDir"/>
<MainUnit Value="0"/> <MainUnit Value="0"/>
<Title Value="dbexport"/> <Title Value="db_export_import"/>
<ResourceType Value="res"/> <ResourceType Value="res"/>
<UseXPManifest Value="True"/> <UseXPManifest Value="True"/>
</General> </General>
@ -37,7 +37,7 @@
</RequiredPackages> </RequiredPackages>
<Units Count="2"> <Units Count="2">
<Unit0> <Unit0>
<Filename Value="dbexport.lpr"/> <Filename Value="db_export_import.lpr"/>
<IsPartOfProject Value="True"/> <IsPartOfProject Value="True"/>
</Unit0> </Unit0>
<Unit1> <Unit1>
@ -54,7 +54,7 @@
<Version Value="11"/> <Version Value="11"/>
<PathDelim Value="\"/> <PathDelim Value="\"/>
<Target> <Target>
<Filename Value="dbexport"/> <Filename Value="db_export_import"/>
</Target> </Target>
<SearchPaths> <SearchPaths>
<IncludeFiles Value="$(ProjOutDir)"/> <IncludeFiles Value="$(ProjOutDir)"/>

View File

@ -1,4 +1,4 @@
program dbexport; program db_export_import;
{$mode objfpc}{$H+} {$mode objfpc}{$H+}

View File

@ -1,34 +1,34 @@
object Form1: TForm1 object Form1: TForm1
Left = 340 Left = 340
Height = 236 Height = 310
Top = 154 Top = 154
Width = 450 Width = 639
Caption = 'db_Export_Import' Caption = 'db_Export_Import'
ClientHeight = 236 ClientHeight = 310
ClientWidth = 450 ClientWidth = 639
OnCreate = FormCreate OnCreate = FormCreate
OnDestroy = FormDestroy OnDestroy = FormDestroy
LCLVersion = '1.3' LCLVersion = '1.3'
object PageControl: TPageControl object PageControl: TPageControl
Left = 4 Left = 4
Height = 228 Height = 302
Top = 4 Top = 4
Width = 442 Width = 631
ActivePage = TabImport ActivePage = TabDataGenerator
Align = alClient Align = alClient
BorderSpacing.Around = 4 BorderSpacing.Around = 4
TabIndex = 2 TabIndex = 0
TabOrder = 0 TabOrder = 0
OnChange = PageControlChange OnChange = PageControlChange
object TabDataGenerator: TTabSheet object TabDataGenerator: TTabSheet
Caption = '1 - Create database' Caption = '1 - Create database'
ClientHeight = 200 ClientHeight = 269
ClientWidth = 434 ClientWidth = 623
object Label2: TLabel object Label2: TLabel
Left = 4 Left = 4
Height = 15 Height = 20
Top = 4 Top = 4
Width = 426 Width = 615
Align = alTop Align = alTop
BorderSpacing.Around = 4 BorderSpacing.Around = 4
Caption = 'Create a database with random records' Caption = 'Create a database with random records'
@ -38,35 +38,35 @@ object Form1: TForm1
end end
object Panel1: TPanel object Panel1: TPanel
Left = 0 Left = 0
Height = 177 Height = 241
Top = 23 Top = 28
Width = 434 Width = 623
Align = alClient Align = alClient
BevelOuter = bvNone BevelOuter = bvNone
ClientHeight = 177 ClientHeight = 241
ClientWidth = 434 ClientWidth = 623
TabOrder = 0 TabOrder = 0
object HeaderLabel1: TLabel object HeaderLabel1: TLabel
Left = 8 Left = 8
Height = 15 Height = 20
Top = 11 Top = 11
Width = 71 Width = 88
Caption = 'Record count' Caption = 'Record count'
ParentColor = False ParentColor = False
end end
object EdRecordCount: TEdit object EdRecordCount: TEdit
Left = 107 Left = 107
Height = 23 Height = 28
Top = 8 Top = 8
Width = 64 Width = 64
Alignment = taRightJustify Alignment = taRightJustify
TabOrder = 0 TabOrder = 0
Text = '10000' Text = '50000'
end end
object BtnCreateDbf: TButton object BtnCreateDbf: TButton
Left = 326 Left = 515
Height = 25 Height = 28
Top = 123 Top = 208
Width = 99 Width = 99
Anchors = [akRight, akBottom] Anchors = [akRight, akBottom]
Caption = 'Run' Caption = 'Run'
@ -77,25 +77,25 @@ object Form1: TForm1
Left = 0 Left = 0
Height = 3 Height = 3
Top = 0 Top = 0
Width = 434 Width = 623
Align = alTop Align = alTop
Shape = bsTopLine Shape = bsTopLine
end end
object InfoLabel1: TLabel object InfoLabel1: TLabel
Left = 4 Left = 8
Height = 15 Height = 20
Top = 158 Top = 216
Width = 426 Width = 496
Align = alBottom Anchors = [akLeft, akRight, akBottom]
BorderSpacing.Around = 4 BorderSpacing.Around = 4
Caption = 'InfoLabe1' Caption = 'InfoLabel1'
ParentColor = False ParentColor = False
end end
object Label1: TLabel object Label1: TLabel
Left = 8 Left = 8
Height = 15 Height = 20
Top = 40 Top = 40
Width = 324 Width = 409
Caption = 'Please note: the binary xls files can handle only 65536 records.' Caption = 'Please note: the binary xls files can handle only 65536 records.'
ParentColor = False ParentColor = False
end end
@ -103,13 +103,13 @@ object Form1: TForm1
end end
object TabExport: TTabSheet object TabExport: TTabSheet
Caption = '2 - Export to spreadsheet' Caption = '2 - Export to spreadsheet'
ClientHeight = 200 ClientHeight = 269
ClientWidth = 434 ClientWidth = 623
object HeaderLabel2: TLabel object HeaderLabel2: TLabel
Left = 4 Left = 4
Height = 15 Height = 20
Top = 4 Top = 4
Width = 426 Width = 615
Align = alTop Align = alTop
BorderSpacing.Around = 4 BorderSpacing.Around = 4
Caption = 'Export database table to spreadsheet file' Caption = 'Export database table to spreadsheet file'
@ -120,26 +120,26 @@ object Form1: TForm1
object Bevel2: TBevel object Bevel2: TBevel
Left = 0 Left = 0
Height = 3 Height = 3
Top = 23 Top = 28
Width = 434 Width = 623
Align = alTop Align = alTop
Shape = bsTopLine Shape = bsTopLine
end end
object InfoLabel2: TLabel object InfoLabel2: TLabel
Left = 4 Left = 8
Height = 15 Height = 20
Top = 181 Top = 244
Width = 426 Width = 504
Align = alBottom Anchors = [akLeft, akRight, akBottom]
BorderSpacing.Around = 4 BorderSpacing.Around = 4
Caption = 'InfoLabel2' Caption = 'InfoLabel2'
ParentColor = False ParentColor = False
end end
object RgFileFormat: TRadioGroup object RgFileFormat: TRadioGroup
Left = 8 Left = 8
Height = 134 Height = 158
Top = 32 Top = 32
Width = 185 Width = 232
AutoFill = True AutoFill = True
Caption = 'Spreadsheet file format' Caption = 'Spreadsheet file format'
ChildSizing.LeftRightSpacing = 6 ChildSizing.LeftRightSpacing = 6
@ -149,8 +149,8 @@ object Form1: TForm1
ChildSizing.ShrinkVertical = crsScaleChilds ChildSizing.ShrinkVertical = crsScaleChilds
ChildSizing.Layout = cclLeftToRightThenTopToBottom ChildSizing.Layout = cclLeftToRightThenTopToBottom
ChildSizing.ControlsPerLine = 1 ChildSizing.ControlsPerLine = 1
ClientHeight = 116 ClientHeight = 136
ClientWidth = 181 ClientWidth = 228
ItemIndex = 2 ItemIndex = 2
Items.Strings = ( Items.Strings = (
'xls (Excel 2)' 'xls (Excel 2)'
@ -162,9 +162,9 @@ object Form1: TForm1
TabOrder = 0 TabOrder = 0
end end
object BtnExport: TButton object BtnExport: TButton
Left = 326 Left = 515
Height = 25 Height = 28
Top = 147 Top = 236
Width = 99 Width = 99
Anchors = [akRight, akBottom] Anchors = [akRight, akBottom]
Caption = 'Run' Caption = 'Run'
@ -174,13 +174,13 @@ object Form1: TForm1
end end
object TabImport: TTabSheet object TabImport: TTabSheet
Caption = '3 - Import from spreadsheet' Caption = '3 - Import from spreadsheet'
ClientHeight = 200 ClientHeight = 269
ClientWidth = 434 ClientWidth = 623
object HeaderLabel3: TLabel object HeaderLabel3: TLabel
Left = 4 Left = 4
Height = 15 Height = 20
Top = 4 Top = 4
Width = 426 Width = 615
Align = alTop Align = alTop
BorderSpacing.Around = 4 BorderSpacing.Around = 4
Caption = 'Import spreadsheet file in database table' Caption = 'Import spreadsheet file in database table'
@ -191,44 +191,47 @@ object Form1: TForm1
object Bevel3: TBevel object Bevel3: TBevel
Left = 0 Left = 0
Height = 3 Height = 3
Top = 23 Top = 28
Width = 434 Width = 623
Align = alTop Align = alTop
Shape = bsTopLine Shape = bsTopLine
end end
object InfoLabel3: TLabel object InfoLabel3: TLabel
Left = 4 Left = 8
Height = 15 Height = 20
Top = 181 Top = 244
Width = 426 Width = 70
Align = alBottom Anchors = [akLeft, akBottom]
BorderSpacing.Around = 4 BorderSpacing.Around = 4
Caption = 'InfoLabel3' Caption = 'InfoLabel3'
ParentColor = False ParentColor = False
end end
object BtnImport: TButton object BtnImport: TButton
Left = 326 Left = 515
Height = 25 Height = 28
Top = 147 Top = 236
Width = 99 Width = 99
Anchors = [akRight, akBottom] Anchors = [akRight, akBottom]
Caption = 'Run' Caption = 'Run'
Enabled = False
OnClick = BtnImportClick OnClick = BtnImportClick
TabOrder = 0 TabOrder = 0
end end
object FileList: TListBox object FileList: TListBox
Left = 6 Left = 8
Height = 121 Height = 181
Top = 56 Top = 56
Width = 292 Width = 292
Anchors = [akTop, akLeft, akBottom]
ItemHeight = 0 ItemHeight = 0
OnClick = FileListClick
TabOrder = 1 TabOrder = 1
end end
object Label3: TLabel object Label3: TLabel
Left = 5 Left = 8
Height = 15 Height = 20
Top = 33 Top = 33
Width = 221 Width = 282
Caption = 'Select the spreadsheet file to be imported:' Caption = 'Select the spreadsheet file to be imported:'
ParentColor = False ParentColor = False
end end

View File

@ -39,6 +39,7 @@ type
procedure BtnCreateDbfClick(Sender: TObject); procedure BtnCreateDbfClick(Sender: TObject);
procedure BtnExportClick(Sender: TObject); procedure BtnExportClick(Sender: TObject);
procedure BtnImportClick(Sender: TObject); procedure BtnImportClick(Sender: TObject);
procedure FileListClick(Sender: TObject);
procedure FormCreate(Sender: TObject); procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject); procedure FormDestroy(Sender: TObject);
procedure PageControlChange(Sender: TObject); procedure PageControlChange(Sender: TObject);
@ -50,7 +51,7 @@ type
FHeaderTemplateCell: PCell; FHeaderTemplateCell: PCell;
FDateTemplateCell: PCell; FDateTemplateCell: PCell;
FImportedFieldNames: TStringList; FImportedFieldNames: TStringList;
FImportedFieldTypes: Array of TFieldType; FImportedRowCells: Array of TCell;
// For reading: all data for the database is generated here out of the spreadsheet file // For reading: all data for the database is generated here out of the spreadsheet file
procedure ReadCellDataHandler(Sender: TObject; ARow, ACol: Cardinal; procedure ReadCellDataHandler(Sender: TObject; ARow, ACol: Cardinal;
const ADataCell: PCell); const ADataCell: PCell);
@ -69,6 +70,7 @@ implementation
{$R *.lfm} {$R *.lfm}
const const
// Parameters for generating dbf file contents
NUM_LAST_NAMES = 8; NUM_LAST_NAMES = 8;
NUM_FIRST_NAMES = 8; NUM_FIRST_NAMES = 8;
NUM_CITIES = 10; NUM_CITIES = 10;
@ -121,8 +123,11 @@ begin
FExportDataset.CreateTable; FExportDataset.CreateTable;
FExportDataset.Open; FExportDataset.Open;
// We generate random records by combining first names, last names and cities
// defined in the FIRST_NAMES, LAST_NAMES and CITIES arrays. We also add a
// random birthday.
for i:=1 to StrToInt(EdRecordCount.Text) do begin for i:=1 to StrToInt(EdRecordCount.Text) do begin
if (i mod 25) = 0 then if (i mod 1000 = 0) then
begin begin
InfoLabel1.Caption := Format('Adding record %d...', [i]); InfoLabel1.Caption := Format('Adding record %d...', [i]);
Application.ProcessMessages; Application.ProcessMessages;
@ -142,8 +147,12 @@ begin
]); ]);
InfoLabel2.Caption := ''; InfoLabel2.Caption := '';
InfoLabel3.Caption := ''; InfoLabel3.Caption := '';
Application.ProcessMessages;
end; end;
{ This procedure exports the data in the dbf file created by BtnCreateDbfClick
to a spreadsheet file. The workbook operates in virtual mode to minimize
memory load of this process }
procedure TForm1.BtnExportClick(Sender: TObject); procedure TForm1.BtnExportClick(Sender: TObject);
var var
DataFileName: String; DataFileName: String;
@ -152,6 +161,12 @@ begin
InfoLabel2.Caption := ''; InfoLabel2.Caption := '';
Application.ProcessMessages; Application.ProcessMessages;
if RgFileFormat.ItemIndex = 4 then
begin
MessageDlg('Virtual mode is not yet implemented for .ods files.', mtError, [mbOK], 0);
exit;
end;
if FExportDataset = nil then if FExportDataset = nil then
begin begin
FExportDataset := TDbf.Create(self); FExportDataset := TDbf.Create(self);
@ -173,24 +188,28 @@ begin
try try
worksheet := FWorkbook.AddWorksheet(FExportDataset.TableName); worksheet := FWorkbook.AddWorksheet(FExportDataset.TableName);
// Make header line frozen // Make header line frozen - but not in Excel2 where frozen panes do not yet work properly
worksheet.Options := worksheet.Options + [soHasFrozenPanes]; if FILE_FORMATS[RgFileFormat.ItemIndex] <> sfExcel2 then begin
worksheet.TopPaneHeight := 1; worksheet.Options := worksheet.Options + [soHasFrozenPanes];
worksheet.TopPaneHeight := 1;
end;
// Prepare template for header line // Use cell A1 as format template of header line
FHeaderTemplateCell := worksheet.GetCell(0, 0); FHeaderTemplateCell := worksheet.GetCell(0, 0);
worksheet.WriteFontStyle(FHeaderTemplateCell, [fssBold]); worksheet.WriteFontStyle(FHeaderTemplateCell, [fssBold]);
worksheet.WriteFontColor(FHeaderTemplateCell, scWhite);
worksheet.WriteBackgroundColor(FHeaderTemplateCell, scGray); worksheet.WriteBackgroundColor(FHeaderTemplateCell, scGray);
if FILE_FORMATS[RgFileFormat.ItemIndex] <> sfExcel2 then
worksheet.WriteFontColor(FHeaderTemplateCell, scWhite); // Does not look nice in the limited Excel2 format
// Prepare template for date column // Use cell B1 as format template of date column
FDateTemplateCell := worksheet.GetCell(0, 1); FDateTemplateCell := worksheet.GetCell(0, 1);
worksheet.WriteDateTimeFormat(FDateTemplateCell, nfShortDate); worksheet.WriteDateTimeFormat(FDateTemplateCell, nfShortDate);
// Make first three columns a bit wider // Make rows a bit wider
worksheet.WriteColWidth(0, 20); worksheet.WriteColWidth(0, 20);
worksheet.WriteColWidth(1, 20); worksheet.WriteColWidth(1, 20);
worksheet.WriteColWidth(2, 20); worksheet.WriteColWidth(2, 20);
worksheet.WriteCOlWidth(3, 15);
// Setup virtual mode to save memory // Setup virtual mode to save memory
// FWorkbook.Options := FWorkbook.Options + [boVirtualMode, boBufStream]; // FWorkbook.Options := FWorkbook.Options + [boVirtualMode, boBufStream];
@ -208,7 +227,7 @@ begin
InfoLabel2.Caption := Format('Done. Database exported to file "%s" in folder "%s"', [ InfoLabel2.Caption := Format('Done. Database exported to file "%s" in folder "%s"', [
ChangeFileExt(FExportDataset.TableName, FILE_EXT[RgFileFormat.ItemIndex]), ChangeFileExt(FExportDataset.TableName, FILE_EXT[RgFileFormat.ItemIndex]),
FExportDataset.FilePathFull DATADIR
]); ]);
end; end;
@ -264,9 +283,9 @@ begin
FImportedFieldNames := TStringList.Create; FImportedFieldNames := TStringList.Create;
FImportedFieldNames.Clear; FImportedFieldNames.Clear;
// ... and this array stores the field types until we have all information // ... and this array will temporarily store the cells of the second row
// to create the dbf table. // until we have all information to create the dbf table.
SetLength(FImportedFieldTypes, 0); SetLength(FImportedRowCells, 0);
// Create the workbook and activate virtual mode // Create the workbook and activate virtual mode
FWorkbook := TsWorkbook.Create; FWorkbook := TsWorkbook.Create;
@ -277,11 +296,20 @@ begin
// The data are not permanently available in the worksheet and do occupy // The data are not permanently available in the worksheet and do occupy
// memory there - this is virtual mode. // memory there - this is virtual mode.
FWorkbook.ReadFromFile(DataFilename, fmt); FWorkbook.ReadFromFile(DataFilename, fmt);
// We close the ImportDataset after import process has finished:
FImportDataset.Close;
InfoLabel3.Caption := Format('Done. File "%s" imported in database "%s".',
[ExtractFileName(DataFileName), FImportDataset.TableName]);
finally finally
FWorkbook.Free; FWorkbook.Free;
end; end;
end; end;
procedure TForm1.FileListClick(Sender: TObject);
begin
BtnImport.Enabled := (FileList.ItemIndex > -1);
end;
procedure TForm1.FormCreate(Sender: TObject); procedure TForm1.FormCreate(Sender: TObject);
begin begin
InfoLabel1.Caption := ''; InfoLabel1.Caption := '';
@ -316,23 +344,26 @@ begin
until FindNext(sr) <> 0; until FindNext(sr) <> 0;
FindClose(sr); FindClose(sr);
end; end;
BtnImport.Enabled := FileList.ItemIndex > -1;
end; end;
end; end;
{ This is the event handler for reading a spreadsheet file in virtual mode. { This is the event handler for reading a spreadsheet file in virtual mode.
The data are not stored in the worksheet and exist only temporarily. ADataCell has just been read from the spreadsheet file, but will not be added
This event handler picks the data and posts them to the database table. to the workbook and will be discarded. The event handler, however, can pick
Note that we do not make many assumptions on the data structure here. Therefore the data and post them to the database table.
we have to buffer the first two rows of the spreadsheet file until the Note that we do not make too many assumptions on the data structure here.
structure of the table is clear. } Therefore we have to buffer the first two rows of the spreadsheet file until
the structure of the table is clear. }
procedure TForm1.ReadCellDataHandler(Sender: TObject; ARow, Acol: Cardinal; procedure TForm1.ReadCellDataHandler(Sender: TObject; ARow, Acol: Cardinal;
const ADataCell: PCell); const ADataCell: PCell);
var var
i: Integer; i: Integer;
fieldType: TFieldType;
begin begin
// The first row (index 0) holds the field names. We temporarily store the // The first row (index 0) holds the field names. We temporarily store the
// field names in a string list because we don't know the data types of the // field names in a string list because we don't know the data types of the
// cell before we have not read the second row (index 1). // cell until we have not read the second row (index 1).
if ARow = 0 then begin if ARow = 0 then begin
// We know that the first row contains string cells -> no further checks. // We know that the first row contains string cells -> no further checks.
FImportedFieldNames.Add(ADataCell^.UTF8StringValue); FImportedFieldNames.Add(ADataCell^.UTF8StringValue);
@ -341,25 +372,48 @@ begin
// We have to buffer the second row (index 1) as well. When it is fully read // We have to buffer the second row (index 1) as well. When it is fully read
// we can put everything together and create the dfb table. // we can put everything together and create the dfb table.
if ARow = 1 then begin if ARow = 1 then begin
if Length(FImportedFieldTypes) = 0 then if Length(FImportedRowCells) = 0 then
SetLength(FImportedFieldTypes, FImportedFieldNames.Count); SetLength(FImportedRowCells, FImportedFieldNames.Count);
case ADataCell^.ContentType of FImportedRowCells[ACol] := ADataCell^;
cctNumber : FImportedFieldTypes[ACol] := ftFloat; // The row is read completely, all field types are known --> we create the table
cctUTF8String: FImportedFieldTypes[ACol] := ftString; if ACol = High(FImportedRowCells) then begin
cctDateTime : FImportedFieldTypes[ACol] := ftDate; // Add fields - the required information is stored in FImportedFieldNames
end; // and FImportedFieldTypes
// All field types are known --> we create the table for i:=0 to High(FImportedRowCells) do begin
if ACol = High(FImportedFieldTypes) then begin case FImportedRowCells[i].ContentType of
for i:=0 to High(FImportedFieldTypes) do cctNumber : fieldType := ftFloat;
FImportDataset.FieldDefs.Add(FImportedFieldNames[i], FImportedFieldTypes[i]); cctDateTime : fieldType := ftDateTime;
cctUTF8String : fieldType := ftString;
end;
FImportDataset.FieldDefs.Add(FImportedFieldNames[i], fieldType);
end;
// Create the table and open it
DeleteFile(FImportDataset.FilePathFull + FImportDataset.TableName); DeleteFile(FImportDataset.FilePathFull + FImportDataset.TableName);
FImportDataset.CreateTable; FImportDataset.CreateTable;
FImportDataset.Open; FImportDataset.Open;
// Now we have to post the cells of the buffered row, otherwise these data
// will be lost
FImportDataset.Insert;
for i:=0 to High(FImportedRowCells) do
case FImportedRowCells[i].ContentType of
cctNumber : FImportDataset.Fields[i].AsFloat := FImportedRowCells[i].NumberValue;
cctDateTime : FImportDataset.Fields[i].AsDateTime := FImportedRowCells[i].DateTimeValue;
cctUTF8String: FImportDataset.Fields[i].AsString := FImportedRowCells[i].UTF8StringValue;
end;
FImportDataset.Post;
// Finally we dispose the buffered cells, we don't need them any more
SetLength(FImportedRowCells, 0);
end; end;
end end
else else
begin begin
// Now that we know everything we can add the data to the table // Now that we know everything we can add the data to the table
if ARow mod 25 = 0 then
begin
InfoLabel3.Caption := Format('Writing row %d to database...', [ARow]);
Application.ProcessMessages;
end;
if ACol = 0 then if ACol = 0 then
FImportDataset.Insert; FImportDataset.Insert;
case ADataCell^.ContentType of case ADataCell^.ContentType of
@ -367,8 +421,8 @@ begin
cctUTF8String: FImportDataset.Fields[Acol].AsString := ADataCell^.UTF8StringValue; cctUTF8String: FImportDataset.Fields[Acol].AsString := ADataCell^.UTF8StringValue;
cctDateTime : FImportDataset.Fields[ACol].AsDateTime := ADataCell^.DateTimeValue; cctDateTime : FImportDataset.Fields[ACol].AsDateTime := ADataCell^.DateTimeValue;
end; end;
if ACol = High(FImportedFieldTypes) then if ACol = FImportedFieldNames.Count-1 then
FImportDataset.Post; FImportDataset.Post; // We post the data after the last cell of the row has been received.
end; end;
end; end;
@ -386,16 +440,20 @@ begin
FExportDataset.First; FExportDataset.First;
end end
else else
// After the header line we write the record data. Note that we are responsible
// for advancing the dataset cursor whenever a row is complete.
begin begin
AValue := FExportDataset.Fields[ACol].Value; AValue := FExportDataset.Fields[ACol].Value;
if FExportDataset.Fields[ACol].DataType = ftDate then if FExportDataset.Fields[ACol].DataType = ftDate then
AStyleCell := FDateTemplateCell; AStyleCell := FDateTemplateCell;
if ACol = FWorkbook.VirtualColCount-1 then if ACol = FWorkbook.VirtualColCount-1 then
begin begin
// Move to next record after last field has been written
FExportDataset.Next; FExportDataset.Next;
if (ARow-1) mod 25 = 0 then // Progress display
if (ARow-1) mod 1000 = 0 then
begin begin
InfoLabel1.Caption := Format('Writing record %d...', [ARow-1]); InfoLabel2.Caption := Format('Writing record %d to spreadsheet...', [ARow-1]);
Application.ProcessMessages; Application.ProcessMessages;
end; end;
end; end;

View File

@ -1,11 +1,12 @@
This example program shows how a large database table can be exported to a This example program shows how a large database table can be exported to and
spreadsheet file using virtual mode. imported from a spreadsheet file using virtual mode.
First, run the section 1 to create a dBase file with random data. First, run the section 1 to create a dBase file with random data.
Then, in section 2, the dBase file can be converted to any spreadsheet format Then, in section 2, the dBase file can be converted to any spreadsheet format
supported. supported. Finally, in section 3, another dBase file can be created from a
selected spreadsheet file.
Please note that this example is mainly educational to show a "real-world" Please note that this example is mainly educational to show a "real-world"
application of virtual mode, but, strictly speaking, virtual mode would not application of virtual mode, but, strictly speaking, virtual mode would not
be absolutely necessary due to the small number of columns. be absolutely necessary due to the small number of columns.
fpspreadsheet.

View File

@ -37,6 +37,11 @@ type
procedure TestWriteRead_BIFF2_HideGridLines_ShowHeaders; procedure TestWriteRead_BIFF2_HideGridLines_ShowHeaders;
procedure TestWriteRead_BIFF2_HideGridLines_HideHeaders; procedure TestWriteRead_BIFF2_HideGridLines_HideHeaders;
procedure TestWriteRead_BIFF2_Panes_HorVert;
procedure TestWriteRead_BIFF2_Panes_Hor;
procedure TestWriteRead_BIFF2_Panes_Vert;
procedure TestWriteRead_BIFF2_Panes_None;
{ BIFF5 tests } { BIFF5 tests }
procedure TestWriteRead_BIFF5_ShowGridLines_ShowHeaders; procedure TestWriteRead_BIFF5_ShowGridLines_ShowHeaders;
procedure TestWriteRead_BIFF5_ShowGridLines_HideHeaders; procedure TestWriteRead_BIFF5_ShowGridLines_HideHeaders;
@ -310,6 +315,28 @@ begin
end; end;
end; end;
{ Tests for BIFF2 frozen panes }
procedure TSpreadWriteReadOptionsTests.TestWriteRead_BIFF2_Panes_HorVert;
begin
TestWriteReadPanes(sfExcel2, 1, 2);
end;
procedure TSpreadWriteReadOptionsTests.TestWriteRead_BIFF2_Panes_Hor;
begin
TestWriteReadPanes(sfExcel2, 1, 0);
end;
procedure TSpreadWriteReadOptionsTests.TestWriteRead_BIFF2_Panes_Vert;
begin
TestWriteReadPanes(sfExcel2, 0, 2);
end;
procedure TSpreadWriteReadOptionsTests.TestWriteRead_BIFF2_Panes_None;
begin
TestWriteReadPanes(sfExcel2, 0, 0);
end;
{ Tests for BIFF5 frozen panes } { Tests for BIFF5 frozen panes }
procedure TSpreadWriteReadOptionsTests.TestWriteRead_BIFF5_Panes_HorVert; procedure TSpreadWriteReadOptionsTests.TestWriteRead_BIFF5_Panes_HorVert;
begin begin

View File

@ -54,7 +54,6 @@ type
TsSpreadBIFF2Reader = class(TsSpreadBIFFReader) TsSpreadBIFF2Reader = class(TsSpreadBIFFReader)
private private
WorkBookEncoding: TsEncoding; WorkBookEncoding: TsEncoding;
FWorksheet: TsWorksheet;
FFont: TsFont; FFont: TsFont;
protected protected
procedure ApplyCellFormatting(ACell: PCell; XFIndex: Word); override; procedure ApplyCellFormatting(ACell: PCell; XFIndex: Word); override;