You've already forked lazarus-ccr
* fpspreadsheet: db_import_export example: add fpsexport method to existing virtual mode code.
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@3708 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
@@ -22,11 +22,11 @@ object Form1: TForm1
|
|||||||
OnChange = PageControlChange
|
OnChange = PageControlChange
|
||||||
object TabDataGenerator: TTabSheet
|
object TabDataGenerator: TTabSheet
|
||||||
Caption = '1 - Create database'
|
Caption = '1 - Create database'
|
||||||
ClientHeight = 274
|
ClientHeight = 276
|
||||||
ClientWidth = 623
|
ClientWidth = 623
|
||||||
object Label2: TLabel
|
object Label2: TLabel
|
||||||
Left = 4
|
Left = 4
|
||||||
Height = 15
|
Height = 13
|
||||||
Top = 4
|
Top = 4
|
||||||
Width = 615
|
Width = 615
|
||||||
Align = alTop
|
Align = alTop
|
||||||
@@ -38,25 +38,25 @@ object Form1: TForm1
|
|||||||
end
|
end
|
||||||
object Panel1: TPanel
|
object Panel1: TPanel
|
||||||
Left = 0
|
Left = 0
|
||||||
Height = 251
|
Height = 255
|
||||||
Top = 23
|
Top = 21
|
||||||
Width = 623
|
Width = 623
|
||||||
Align = alClient
|
Align = alClient
|
||||||
BevelOuter = bvNone
|
BevelOuter = bvNone
|
||||||
ClientHeight = 251
|
ClientHeight = 255
|
||||||
ClientWidth = 623
|
ClientWidth = 623
|
||||||
TabOrder = 0
|
TabOrder = 0
|
||||||
object HeaderLabel1: TLabel
|
object HeaderLabel1: TLabel
|
||||||
Left = 8
|
Left = 8
|
||||||
Height = 15
|
Height = 13
|
||||||
Top = 11
|
Top = 11
|
||||||
Width = 71
|
Width = 64
|
||||||
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 = 21
|
||||||
Top = 8
|
Top = 8
|
||||||
Width = 64
|
Width = 64
|
||||||
Alignment = taRightJustify
|
Alignment = taRightJustify
|
||||||
@@ -66,7 +66,7 @@ object Form1: TForm1
|
|||||||
object BtnCreateDbf: TButton
|
object BtnCreateDbf: TButton
|
||||||
Left = 515
|
Left = 515
|
||||||
Height = 28
|
Height = 28
|
||||||
Top = 218
|
Top = 222
|
||||||
Width = 99
|
Width = 99
|
||||||
Anchors = [akRight, akBottom]
|
Anchors = [akRight, akBottom]
|
||||||
Caption = 'Run'
|
Caption = 'Run'
|
||||||
@@ -83,8 +83,8 @@ object Form1: TForm1
|
|||||||
end
|
end
|
||||||
object InfoLabel1: TLabel
|
object InfoLabel1: TLabel
|
||||||
Left = 8
|
Left = 8
|
||||||
Height = 15
|
Height = 13
|
||||||
Top = 231
|
Top = 237
|
||||||
Width = 496
|
Width = 496
|
||||||
Anchors = [akLeft, akRight, akBottom]
|
Anchors = [akLeft, akRight, akBottom]
|
||||||
BorderSpacing.Around = 4
|
BorderSpacing.Around = 4
|
||||||
@@ -93,9 +93,9 @@ object Form1: TForm1
|
|||||||
end
|
end
|
||||||
object Label1: TLabel
|
object Label1: TLabel
|
||||||
Left = 8
|
Left = 8
|
||||||
Height = 15
|
Height = 13
|
||||||
Top = 40
|
Top = 40
|
||||||
Width = 324
|
Width = 304
|
||||||
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,11 +103,11 @@ object Form1: TForm1
|
|||||||
end
|
end
|
||||||
object TabExport: TTabSheet
|
object TabExport: TTabSheet
|
||||||
Caption = '2 - Export to spreadsheet'
|
Caption = '2 - Export to spreadsheet'
|
||||||
ClientHeight = 269
|
ClientHeight = 276
|
||||||
ClientWidth = 623
|
ClientWidth = 623
|
||||||
object HeaderLabel2: TLabel
|
object HeaderLabel2: TLabel
|
||||||
Left = 4
|
Left = 4
|
||||||
Height = 20
|
Height = 13
|
||||||
Top = 4
|
Top = 4
|
||||||
Width = 615
|
Width = 615
|
||||||
Align = alTop
|
Align = alTop
|
||||||
@@ -120,15 +120,15 @@ object Form1: TForm1
|
|||||||
object Bevel2: TBevel
|
object Bevel2: TBevel
|
||||||
Left = 0
|
Left = 0
|
||||||
Height = 3
|
Height = 3
|
||||||
Top = 28
|
Top = 21
|
||||||
Width = 623
|
Width = 623
|
||||||
Align = alTop
|
Align = alTop
|
||||||
Shape = bsTopLine
|
Shape = bsTopLine
|
||||||
end
|
end
|
||||||
object InfoLabel2: TLabel
|
object InfoLabel2: TLabel
|
||||||
Left = 8
|
Left = 8
|
||||||
Height = 20
|
Height = 13
|
||||||
Top = 244
|
Top = 258
|
||||||
Width = 504
|
Width = 504
|
||||||
Anchors = [akLeft, akRight, akBottom]
|
Anchors = [akLeft, akRight, akBottom]
|
||||||
BorderSpacing.Around = 4
|
BorderSpacing.Around = 4
|
||||||
@@ -149,7 +149,7 @@ object Form1: TForm1
|
|||||||
ChildSizing.ShrinkVertical = crsScaleChilds
|
ChildSizing.ShrinkVertical = crsScaleChilds
|
||||||
ChildSizing.Layout = cclLeftToRightThenTopToBottom
|
ChildSizing.Layout = cclLeftToRightThenTopToBottom
|
||||||
ChildSizing.ControlsPerLine = 1
|
ChildSizing.ControlsPerLine = 1
|
||||||
ClientHeight = 138
|
ClientHeight = 140
|
||||||
ClientWidth = 228
|
ClientWidth = 228
|
||||||
ItemIndex = 2
|
ItemIndex = 2
|
||||||
Items.Strings = (
|
Items.Strings = (
|
||||||
@@ -164,21 +164,44 @@ object Form1: TForm1
|
|||||||
object BtnExport: TButton
|
object BtnExport: TButton
|
||||||
Left = 515
|
Left = 515
|
||||||
Height = 28
|
Height = 28
|
||||||
Top = 236
|
Top = 243
|
||||||
Width = 99
|
Width = 99
|
||||||
Anchors = [akRight, akBottom]
|
Anchors = [akRight, akBottom]
|
||||||
Caption = 'Run'
|
Caption = 'Run'
|
||||||
OnClick = BtnExportClick
|
OnClick = BtnExportClick
|
||||||
TabOrder = 1
|
TabOrder = 1
|
||||||
end
|
end
|
||||||
|
object RgExportMode: TRadioGroup
|
||||||
|
Left = 256
|
||||||
|
Height = 158
|
||||||
|
Top = 32
|
||||||
|
Width = 232
|
||||||
|
AutoFill = True
|
||||||
|
Caption = 'Export method'
|
||||||
|
ChildSizing.LeftRightSpacing = 6
|
||||||
|
ChildSizing.EnlargeHorizontal = crsHomogenousChildResize
|
||||||
|
ChildSizing.EnlargeVertical = crsHomogenousChildResize
|
||||||
|
ChildSizing.ShrinkHorizontal = crsScaleChilds
|
||||||
|
ChildSizing.ShrinkVertical = crsScaleChilds
|
||||||
|
ChildSizing.Layout = cclLeftToRightThenTopToBottom
|
||||||
|
ChildSizing.ControlsPerLine = 1
|
||||||
|
ClientHeight = 140
|
||||||
|
ClientWidth = 228
|
||||||
|
ItemIndex = 0
|
||||||
|
Items.Strings = (
|
||||||
|
'Virtual mode (memory saving)'
|
||||||
|
'FPSExport'
|
||||||
|
)
|
||||||
|
TabOrder = 2
|
||||||
|
end
|
||||||
end
|
end
|
||||||
object TabImport: TTabSheet
|
object TabImport: TTabSheet
|
||||||
Caption = '3 - Import from spreadsheet'
|
Caption = '3 - Import from spreadsheet'
|
||||||
ClientHeight = 269
|
ClientHeight = 276
|
||||||
ClientWidth = 623
|
ClientWidth = 623
|
||||||
object HeaderLabel3: TLabel
|
object HeaderLabel3: TLabel
|
||||||
Left = 4
|
Left = 4
|
||||||
Height = 20
|
Height = 13
|
||||||
Top = 4
|
Top = 4
|
||||||
Width = 615
|
Width = 615
|
||||||
Align = alTop
|
Align = alTop
|
||||||
@@ -191,16 +214,16 @@ object Form1: TForm1
|
|||||||
object Bevel3: TBevel
|
object Bevel3: TBevel
|
||||||
Left = 0
|
Left = 0
|
||||||
Height = 3
|
Height = 3
|
||||||
Top = 28
|
Top = 21
|
||||||
Width = 623
|
Width = 623
|
||||||
Align = alTop
|
Align = alTop
|
||||||
Shape = bsTopLine
|
Shape = bsTopLine
|
||||||
end
|
end
|
||||||
object InfoLabel3: TLabel
|
object InfoLabel3: TLabel
|
||||||
Left = 8
|
Left = 8
|
||||||
Height = 20
|
Height = 13
|
||||||
Top = 244
|
Top = 258
|
||||||
Width = 70
|
Width = 51
|
||||||
Anchors = [akLeft, akBottom]
|
Anchors = [akLeft, akBottom]
|
||||||
BorderSpacing.Around = 4
|
BorderSpacing.Around = 4
|
||||||
Caption = 'InfoLabel3'
|
Caption = 'InfoLabel3'
|
||||||
@@ -209,7 +232,7 @@ object Form1: TForm1
|
|||||||
object BtnImport: TButton
|
object BtnImport: TButton
|
||||||
Left = 515
|
Left = 515
|
||||||
Height = 28
|
Height = 28
|
||||||
Top = 236
|
Top = 243
|
||||||
Width = 99
|
Width = 99
|
||||||
Anchors = [akRight, akBottom]
|
Anchors = [akRight, akBottom]
|
||||||
Caption = 'Run'
|
Caption = 'Run'
|
||||||
@@ -219,7 +242,7 @@ object Form1: TForm1
|
|||||||
end
|
end
|
||||||
object FileList: TListBox
|
object FileList: TListBox
|
||||||
Left = 8
|
Left = 8
|
||||||
Height = 181
|
Height = 188
|
||||||
Top = 56
|
Top = 56
|
||||||
Width = 292
|
Width = 292
|
||||||
Anchors = [akTop, akLeft, akBottom]
|
Anchors = [akTop, akLeft, akBottom]
|
||||||
@@ -229,9 +252,9 @@ object Form1: TForm1
|
|||||||
end
|
end
|
||||||
object Label3: TLabel
|
object Label3: TLabel
|
||||||
Left = 8
|
Left = 8
|
||||||
Height = 20
|
Height = 13
|
||||||
Top = 33
|
Top = 33
|
||||||
Width = 282
|
Width = 205
|
||||||
Caption = 'Select the spreadsheet file to be imported:'
|
Caption = 'Select the spreadsheet file to be imported:'
|
||||||
ParentColor = False
|
ParentColor = False
|
||||||
end
|
end
|
||||||
|
@@ -6,7 +6,7 @@ interface
|
|||||||
|
|
||||||
uses
|
uses
|
||||||
Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
|
Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
|
||||||
ComCtrls, ExtCtrls, db, dbf, fpspreadsheet, fpsallformats;
|
ComCtrls, ExtCtrls, db, dbf, fpspreadsheet, fpsallformats, fpsexport;
|
||||||
|
|
||||||
type
|
type
|
||||||
|
|
||||||
@@ -33,6 +33,7 @@ type
|
|||||||
PageControl: TPageControl;
|
PageControl: TPageControl;
|
||||||
Panel1: TPanel;
|
Panel1: TPanel;
|
||||||
RgFileFormat: TRadioGroup;
|
RgFileFormat: TRadioGroup;
|
||||||
|
RgExportMode: TRadioGroup;
|
||||||
TabDataGenerator: TTabSheet;
|
TabDataGenerator: TTabSheet;
|
||||||
TabExport: TTabSheet;
|
TabExport: TTabSheet;
|
||||||
TabImport: TTabSheet;
|
TabImport: TTabSheet;
|
||||||
@@ -52,10 +53,18 @@ type
|
|||||||
FDateTemplateCell: PCell;
|
FDateTemplateCell: PCell;
|
||||||
FImportedFieldNames: TStringList;
|
FImportedFieldNames: TStringList;
|
||||||
FImportedRowCells: Array of TCell;
|
FImportedRowCells: Array of TCell;
|
||||||
// For reading: all data for the database is generated here out of the spreadsheet file
|
// Actual export code when using FPSpreadsheet's fpsexport:
|
||||||
|
// reads dbf and writes to spreadsheet
|
||||||
|
// Expects FExportDataset to be available
|
||||||
|
procedure ExportUsingFPSExport(var DataFileName: string);
|
||||||
|
// Actual export code when using virtual mode:
|
||||||
|
// reads dbf and writes to spreadsheet
|
||||||
|
// Expects FExportDataset to be available
|
||||||
|
procedure ExportUsingVirtualMode(var DataFileName: string);
|
||||||
|
// Virtual mode: 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);
|
||||||
// For writing: all data for the cells is generated here (out of the .dbf file)
|
// Virtual mode: for writing: all data for the cells is generated here (out of the .dbf file)
|
||||||
procedure WriteCellDataHandler(Sender: TObject; ARow, ACol: Cardinal;
|
procedure WriteCellDataHandler(Sender: TObject; ARow, ACol: Cardinal;
|
||||||
var AValue: variant; var AStyleCell: PCell);
|
var AValue: variant; var AStyleCell: PCell);
|
||||||
public
|
public
|
||||||
@@ -69,6 +78,12 @@ implementation
|
|||||||
|
|
||||||
{$R *.lfm}
|
{$R *.lfm}
|
||||||
|
|
||||||
|
type
|
||||||
|
// Ways to export dbf/dataset. Corresponds to the items
|
||||||
|
// of the RgExportMode radiogroup
|
||||||
|
TsExportModes=(seVirtual {manual coding using Virtual Mode},
|
||||||
|
seFPSExport {uses FpSpreadsheet's fpsexport - takes more memory});
|
||||||
|
|
||||||
const
|
const
|
||||||
// Parameters for generating dbf file contents
|
// Parameters for generating dbf file contents
|
||||||
NUM_LAST_NAMES = 8;
|
NUM_LAST_NAMES = 8;
|
||||||
@@ -88,6 +103,7 @@ const
|
|||||||
DATADIR = 'data'; //subdirectory where .dbf is stored
|
DATADIR = 'data'; //subdirectory where .dbf is stored
|
||||||
|
|
||||||
// File formats corresponding to the items of the RgFileFormat radiogroup
|
// File formats corresponding to the items of the RgFileFormat radiogroup
|
||||||
|
// Items in RadioGroup in Export tab match this order
|
||||||
FILE_FORMATS: array[0..4] of TsSpreadsheetFormat = (
|
FILE_FORMATS: array[0..4] of TsSpreadsheetFormat = (
|
||||||
sfExcel2, sfExcel5, sfExcel8, sfOOXML, sfOpenDocument
|
sfExcel2, sfExcel5, sfExcel8, sfOOXML, sfOpenDocument
|
||||||
);
|
);
|
||||||
@@ -155,18 +171,11 @@ end;
|
|||||||
memory load of this process }
|
memory load of this process }
|
||||||
procedure TForm1.BtnExportClick(Sender: TObject);
|
procedure TForm1.BtnExportClick(Sender: TObject);
|
||||||
var
|
var
|
||||||
DataFileName: String;
|
DataFileName: string; //export file name
|
||||||
worksheet: TsWorksheet;
|
|
||||||
begin
|
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);
|
||||||
@@ -177,52 +186,27 @@ begin
|
|||||||
DataFileName := FExportDataset.FilePathFull + FExportDataset.TableName;
|
DataFileName := FExportDataset.FilePathFull + FExportDataset.TableName;
|
||||||
if not FileExists(DataFileName) then
|
if not FileExists(DataFileName) then
|
||||||
begin
|
begin
|
||||||
MessageDlg(Format('Database file "%s" not found. Please run "Create database" first.',
|
MessageDlg(Format('Database file "%s" not found. Please run "Create '
|
||||||
|
+'database" first.',
|
||||||
[DataFileName]), mtError, [mbOK], 0);
|
[DataFileName]), mtError, [mbOK], 0);
|
||||||
exit;
|
exit;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
FExportDataset.Open;
|
// Make user aware export may take some time by changing cursor
|
||||||
|
Screen.Cursor := crHourGlass;
|
||||||
FWorkbook := TsWorkbook.Create;
|
|
||||||
try
|
try
|
||||||
worksheet := FWorkbook.AddWorksheet(FExportDataset.TableName);
|
InfoLabel1.Caption := ('Starting database export.');
|
||||||
|
case TsExportModes(RgExportMode.ItemIndex) of
|
||||||
// Make header line frozen - but not in Excel2 where frozen panes do not yet work properly
|
seVirtual: ExportUsingVirtualMode(DataFileName);
|
||||||
if FILE_FORMATS[RgFileFormat.ItemIndex] <> sfExcel2 then begin
|
seFPSExport: ExportUsingFPSExport(DataFileName);
|
||||||
worksheet.Options := worksheet.Options + [soHasFrozenPanes];
|
else
|
||||||
worksheet.TopPaneHeight := 1;
|
begin
|
||||||
|
ShowMessageFmt('Unknown export mode number %d. Please correct source code.',[RgExportMode.ItemIndex]);
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
// Use cell A1 as format template of header line
|
|
||||||
FHeaderTemplateCell := worksheet.GetCell(0, 0);
|
|
||||||
worksheet.WriteFontStyle(FHeaderTemplateCell, [fssBold]);
|
|
||||||
worksheet.WriteBackgroundColor(FHeaderTemplateCell, scGray);
|
|
||||||
if FILE_FORMATS[RgFileFormat.ItemIndex] <> sfExcel2 then
|
|
||||||
worksheet.WriteFontColor(FHeaderTemplateCell, scWhite); // Does not look nice in the limited Excel2 format
|
|
||||||
|
|
||||||
// Use cell B1 as format template of date column
|
|
||||||
FDateTemplateCell := worksheet.GetCell(0, 1);
|
|
||||||
worksheet.WriteDateTimeFormat(FDateTemplateCell, nfShortDate);
|
|
||||||
|
|
||||||
// Make rows a bit wider
|
|
||||||
worksheet.WriteColWidth(0, 20);
|
|
||||||
worksheet.WriteColWidth(1, 20);
|
|
||||||
worksheet.WriteColWidth(2, 20);
|
|
||||||
worksheet.WriteColWidth(3, 15);
|
|
||||||
|
|
||||||
// Setup virtual mode to save memory
|
|
||||||
// FWorkbook.Options := FWorkbook.Options + [boVirtualMode, boBufStream];
|
|
||||||
FWorkbook.Options := FWorkbook.Options + [boVirtualMode];
|
|
||||||
FWorkbook.OnWriteCellData := @WriteCellDataHandler;
|
|
||||||
FWorkbook.VirtualRowCount := FExportDataset.RecordCount + 1; // +1 for the header line
|
|
||||||
FWorkbook.VirtualColCount := FExportDataset.FieldCount;
|
|
||||||
|
|
||||||
// Write
|
|
||||||
DataFileName := ChangeFileExt(DataFileName, FILE_EXT[RgFileFormat.ItemIndex]);
|
|
||||||
FWorkbook.WriteToFile(DataFileName, FILE_FORMATS[RgFileFormat.ItemIndex], true);
|
|
||||||
finally
|
finally
|
||||||
FreeAndNil(FWorkbook);
|
Screen.Cursor := crDefault;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
InfoLabel2.Caption := Format('Done. Database exported to file "%s" in folder "%s"', [
|
InfoLabel2.Caption := Format('Done. Database exported to file "%s" in folder "%s"', [
|
||||||
@@ -248,60 +232,113 @@ begin
|
|||||||
// exceptions that occur for Excel2 and Excel5.
|
// exceptions that occur for Excel2 and Excel5.
|
||||||
DataFileName := FileList.Items[FileList.ItemIndex];
|
DataFileName := FileList.Items[FileList.ItemIndex];
|
||||||
ext := lowercase(ExtractFileExt(DataFileName));
|
ext := lowercase(ExtractFileExt(DataFileName));
|
||||||
if ext = '.xls' then begin
|
case ext of
|
||||||
if pos(FILE_EXT[0], DataFileName) > 0 then
|
'.xls':
|
||||||
fmt := sfExcel2
|
begin
|
||||||
|
if pos(FILE_EXT[0], DataFileName) > 0 then
|
||||||
|
fmt := sfExcel2
|
||||||
|
else
|
||||||
|
if pos(FILE_EXT[1], DataFileName) > 0 then
|
||||||
|
fmt := sfExcel5
|
||||||
|
else
|
||||||
|
fmt := sfExcel8;
|
||||||
|
end;
|
||||||
|
'.xlsx':
|
||||||
|
fmt := sfOOXML;
|
||||||
|
'.ods':
|
||||||
|
fmt := sfOpenDocument;
|
||||||
else
|
else
|
||||||
if pos(FILE_EXT[1], DataFileName) > 0 then
|
begin
|
||||||
fmt := sfExcel5
|
MessageDlg('Unknown spreadsheet file format.', mtError, [mbOK], 0);
|
||||||
else
|
exit;
|
||||||
fmt := sfExcel8;
|
end;
|
||||||
end else
|
|
||||||
if ext = '.xlsx' then
|
|
||||||
fmt := sfOOXML
|
|
||||||
else
|
|
||||||
if ext = '.ods' then
|
|
||||||
fmt := sfOpenDocument
|
|
||||||
else begin
|
|
||||||
MessageDlg('Unknown spreadsheet file format.', mtError, [mbOK], 0);
|
|
||||||
exit;
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
DataFileName := DATADIR + DirectorySeparator + DataFileName;
|
// Make user aware import may take some time by changing cursor
|
||||||
|
Screen.Cursor := crHourglass;
|
||||||
// Prepare dbf table for the spreadsheet data to be imported
|
|
||||||
if FImportDataset <> nil then
|
|
||||||
FImportDataset.Free;
|
|
||||||
FImportDataset := TDbf.Create(self);
|
|
||||||
FImportDataset.FilePathFull := DATADIR + DirectorySeparator;
|
|
||||||
FImportDataset.TableName := 'imported_' + TABLENAME;
|
|
||||||
FImportDataset.TableLevel := 4; //DBase IV; most widely used.
|
|
||||||
DeleteFile(FImportDataset.FilePathFull + FImportDataset.TableName);
|
|
||||||
|
|
||||||
// The stringlist will temporarily store the field names ...
|
|
||||||
if FImportedFieldNames = nil then
|
|
||||||
FImportedFieldNames := TStringList.Create;
|
|
||||||
FImportedFieldNames.Clear;
|
|
||||||
|
|
||||||
// ... and this array will temporarily store the cells of the second row
|
|
||||||
// until we have all information to create the dbf table.
|
|
||||||
SetLength(FImportedRowCells, 0);
|
|
||||||
|
|
||||||
// Create the workbook and activate virtual mode
|
|
||||||
FWorkbook := TsWorkbook.Create;
|
|
||||||
try
|
try
|
||||||
FWorkbook.Options := FWorkbook.Options + [boVirtualMode];
|
DataFileName := DATADIR + DirectorySeparator + DataFileName;
|
||||||
FWorkbook.OnReadCellData := @ReadCellDataHandler;
|
|
||||||
// Read the data from the spreadsheet file transparently into the dbf file
|
// Prepare dbf table for the spreadsheet data to be imported
|
||||||
// The data are not permanently available in the worksheet and do not occupy
|
if FImportDataset <> nil then
|
||||||
// memory there - this is virtual mode.
|
FImportDataset.Free;
|
||||||
FWorkbook.ReadFromFile(DataFilename, fmt);
|
FImportDataset := TDbf.Create(self);
|
||||||
// We close the ImportDataset after import process has finished:
|
FImportDataset.FilePathFull := DATADIR + DirectorySeparator;
|
||||||
FImportDataset.Close;
|
FImportDataset.TableName := 'imported_' + TABLENAME;
|
||||||
InfoLabel3.Caption := Format('Done. File "%s" imported in database "%s".',
|
FImportDataset.TableLevel := 4; //DBase IV; most widely used.
|
||||||
[ExtractFileName(DataFileName), FImportDataset.TableName]);
|
DeleteFile(FImportDataset.FilePathFull + FImportDataset.TableName);
|
||||||
|
|
||||||
|
// The stringlist will temporarily store the field names ...
|
||||||
|
if FImportedFieldNames = nil then
|
||||||
|
FImportedFieldNames := TStringList.Create;
|
||||||
|
FImportedFieldNames.Clear;
|
||||||
|
|
||||||
|
// ... and this array will temporarily store the cells of the second row
|
||||||
|
// until we have all information to create the dbf table.
|
||||||
|
SetLength(FImportedRowCells, 0);
|
||||||
|
|
||||||
|
// Create the workbook and activate virtual mode
|
||||||
|
FWorkbook := TsWorkbook.Create;
|
||||||
|
try
|
||||||
|
FWorkbook.Options := FWorkbook.Options + [boVirtualMode];
|
||||||
|
FWorkbook.OnReadCellData := @ReadCellDataHandler;
|
||||||
|
// Read the data from the spreadsheet file transparently into the dbf file
|
||||||
|
// The data are not permanently available in the worksheet and do not occupy
|
||||||
|
// memory there - this is virtual mode.
|
||||||
|
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
|
||||||
|
FWorkbook.Free;
|
||||||
|
end;
|
||||||
finally
|
finally
|
||||||
FWorkbook.Free;
|
Screen.Cursor := crDefault;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TForm1.ExportUsingFPSExport(var DataFileName: string);
|
||||||
|
var
|
||||||
|
Exporter: TFPSExport;
|
||||||
|
ExportSettings: TFPSExportFormatSettings;
|
||||||
|
begin
|
||||||
|
FExportDataset.Open;
|
||||||
|
// TCustomDatasetExporter dsecendants like TFPSExport will start to export
|
||||||
|
// from current record so make sure we get everything
|
||||||
|
FExportDataset.First;
|
||||||
|
|
||||||
|
Exporter := TFPSExport.Create(nil);
|
||||||
|
ExportSettings := TFPSExportFormatSettings.Create(true);
|
||||||
|
try
|
||||||
|
// Write header row with field names
|
||||||
|
ExportSettings.HeaderRow := true;
|
||||||
|
case FILE_FORMATS[RgFileFormat.ItemIndex] of
|
||||||
|
sfExcel2, sfExcel5:
|
||||||
|
begin
|
||||||
|
ShowMessage('Format not supported using this mode.');
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
sfExcel8: ExportSettings.ExportFormat := efXLS;
|
||||||
|
sfOOXML: ExportSettings.ExportFormat := efXLSX;
|
||||||
|
sfOpenDocument: ExportSettings.ExportFormat := efODS;
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
ShowMessage('Unknown export format. Please correct the source code.');
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
// Actually apply settings
|
||||||
|
Exporter.FormatSettings := ExportSettings;
|
||||||
|
|
||||||
|
// Write
|
||||||
|
Exporter.Dataset := FExportDataset;
|
||||||
|
Exporter.FileName := ChangeFileExt(DataFileName, FILE_EXT[
|
||||||
|
RgFileFormat.ItemIndex]);
|
||||||
|
Exporter.Execute;
|
||||||
|
finally
|
||||||
|
Exporter.Free;
|
||||||
|
ExportSettings.Free;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@@ -348,6 +385,62 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TForm1.ExportUsingVirtualMode(var DataFileName: string);
|
||||||
|
var
|
||||||
|
worksheet: TsWorksheet;
|
||||||
|
begin
|
||||||
|
if FILE_FORMATS[RgFileFormat.ItemIndex] = sfOpenDocument then
|
||||||
|
begin
|
||||||
|
MessageDlg('Virtual mode is not yet implemented for .ods files.', mtError, [mbOK], 0);
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
|
||||||
|
FExportDataset.Open;
|
||||||
|
|
||||||
|
FWorkbook := TsWorkbook.Create;
|
||||||
|
try
|
||||||
|
worksheet := FWorkbook.AddWorksheet(FExportDataset.TableName);
|
||||||
|
|
||||||
|
// Make header line frozen - but not in Excel2 where frozen panes do not yet work properly
|
||||||
|
if FILE_FORMATS[RgFileFormat.ItemIndex] <> sfExcel2 then begin
|
||||||
|
worksheet.Options := worksheet.Options + [soHasFrozenPanes];
|
||||||
|
worksheet.TopPaneHeight := 1;
|
||||||
|
end;
|
||||||
|
|
||||||
|
// Use cell A1 as format template of header line
|
||||||
|
FHeaderTemplateCell := worksheet.GetCell(0, 0);
|
||||||
|
worksheet.WriteFontStyle(FHeaderTemplateCell, [fssBold]);
|
||||||
|
worksheet.WriteBackgroundColor(FHeaderTemplateCell, scGray);
|
||||||
|
if FILE_FORMATS[RgFileFormat.ItemIndex] <> sfExcel2 then
|
||||||
|
worksheet.WriteFontColor(FHeaderTemplateCell, scWhite); // Does not look nice in the limited Excel2 format
|
||||||
|
|
||||||
|
// Use cell B1 as format template of date column
|
||||||
|
FDateTemplateCell := worksheet.GetCell(0, 1);
|
||||||
|
worksheet.WriteDateTimeFormat(FDateTemplateCell, nfShortDate);
|
||||||
|
|
||||||
|
// Make rows a bit wider
|
||||||
|
worksheet.WriteColWidth(0, 20);
|
||||||
|
worksheet.WriteColWidth(1, 20);
|
||||||
|
worksheet.WriteColWidth(2, 20);
|
||||||
|
worksheet.WriteColWidth(3, 15);
|
||||||
|
|
||||||
|
// Setup virtual mode to save memory
|
||||||
|
// FWorkbook.Options := FWorkbook.Options + [boVirtualMode, boBufStream];
|
||||||
|
FWorkbook.Options := FWorkbook.Options + [boVirtualMode];
|
||||||
|
FWorkbook.OnWriteCellData := @WriteCellDataHandler;
|
||||||
|
FWorkbook.VirtualRowCount := FExportDataset.RecordCount + 1; // +1 for the header line
|
||||||
|
FWorkbook.VirtualColCount := FExportDataset.FieldCount;
|
||||||
|
|
||||||
|
// Write
|
||||||
|
DataFileName := ChangeFileExt(DataFileName, FILE_EXT[
|
||||||
|
RgFileFormat.ItemIndex]);
|
||||||
|
FWorkbook.WriteToFile(DataFileName, FILE_FORMATS[RgFileFormat.ItemIndex],
|
||||||
|
true);
|
||||||
|
finally
|
||||||
|
FreeAndNil(FWorkbook);
|
||||||
|
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.
|
||||||
ADataCell has just been read from the spreadsheet file, but will not be added
|
ADataCell has just been read from the spreadsheet file, but will not be added
|
||||||
to the workbook and will be discarded. The event handler, however, can pick
|
to the workbook and will be discarded. The event handler, however, can pick
|
||||||
@@ -355,7 +448,7 @@ end;
|
|||||||
Note that we do not make too many assumptions on the data structure here.
|
Note that we do not make too many assumptions on the data structure here.
|
||||||
Therefore we have to buffer the first two rows of the spreadsheet file until
|
Therefore we have to buffer the first two rows of the spreadsheet file until
|
||||||
the structure of the table is clear. }
|
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;
|
||||||
@@ -375,7 +468,8 @@ begin
|
|||||||
if Length(FImportedRowCells) = 0 then
|
if Length(FImportedRowCells) = 0 then
|
||||||
SetLength(FImportedRowCells, FImportedFieldNames.Count);
|
SetLength(FImportedRowCells, FImportedFieldNames.Count);
|
||||||
FImportedRowCells[ACol] := ADataCell^;
|
FImportedRowCells[ACol] := ADataCell^;
|
||||||
// The row is read completely, all field types are known --> we create the table
|
// The row is read completely, all field types are known --> we create the
|
||||||
|
// table
|
||||||
if ACol = High(FImportedRowCells) then begin
|
if ACol = High(FImportedRowCells) then begin
|
||||||
// Add fields - the required information is stored in FImportedFieldNames
|
// Add fields - the required information is stored in FImportedFieldNames
|
||||||
// and FImportedFieldTypes
|
// and FImportedFieldTypes
|
||||||
@@ -440,8 +534,8 @@ begin
|
|||||||
FExportDataset.First;
|
FExportDataset.First;
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
// After the header line we write the record data. Note that we are responsible
|
// After the header line we write the record data. Note that we are
|
||||||
// for advancing the dataset cursor whenever a row is complete.
|
// 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
|
||||||
|
@@ -1,11 +1,17 @@
|
|||||||
This example program shows how a large database table can be exported to and
|
This example program shows how a large database table can be exported to a
|
||||||
imported from a spreadsheet file using virtual mode.
|
spreadsheet using virtual mode or fpspreadsheet's fpsexport.
|
||||||
|
It also shows importing a spreadsheet file into a database 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. Finally, in section 3, another dBase file can be created from a
|
supported. Finally, in section 3, another dBase file can be created from a
|
||||||
selected spreadsheet file.
|
selected spreadsheet file.
|
||||||
|
|
||||||
|
Export using virtual mode has the advantage that this takes less memory for the
|
||||||
|
spreadsheet contents, but requires some more coding. It is also quite fast.
|
||||||
|
Exporting using fpsexport needs less code but takes more memory (important for
|
||||||
|
large amounts of data) and seems slower.
|
||||||
|
|
||||||
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.
|
||||||
|
@@ -79,11 +79,12 @@ Type
|
|||||||
property Dataset;
|
property Dataset;
|
||||||
{@@ Fields to be exported }
|
{@@ Fields to be exported }
|
||||||
property ExportFields;
|
property ExportFields;
|
||||||
|
{@@ Settings - e.g. export format - to be used }
|
||||||
|
property FormatSettings;
|
||||||
{@@ Export starting from current record or beginning. }
|
{@@ Export starting from current record or beginning. }
|
||||||
property FromCurrent;
|
property FromCurrent;
|
||||||
{@@ Flag indicating whether to return to current dataset position after export }
|
{@@ Flag indicating whether to return to current dataset position after export }
|
||||||
property RestorePosition;
|
property RestorePosition;
|
||||||
property FormatSettings;
|
|
||||||
{@@ Procedure to run when exporting a row }
|
{@@ Procedure to run when exporting a row }
|
||||||
property OnExportRow;
|
property OnExportRow;
|
||||||
end;
|
end;
|
||||||
@@ -237,7 +238,7 @@ end;
|
|||||||
procedure TFPSExportFormatSettings.InitSettings;
|
procedure TFPSExportFormatSettings.InitSettings;
|
||||||
begin
|
begin
|
||||||
inherited InitSettings;
|
inherited InitSettings;
|
||||||
FExportFormat:=efXLS; //often used
|
FExportFormat:=efXLS; //often used format
|
||||||
end;
|
end;
|
||||||
|
|
||||||
end.
|
end.
|
||||||
|
Reference in New Issue
Block a user