diff --git a/components/fpspreadsheet/examples/excel8demo/excel8read.lpi b/components/fpspreadsheet/examples/excel8demo/excel8read.lpi
index 06e6eaccf..4a961d8b1 100644
--- a/components/fpspreadsheet/examples/excel8demo/excel8read.lpi
+++ b/components/fpspreadsheet/examples/excel8demo/excel8read.lpi
@@ -14,7 +14,7 @@
-
+
@@ -25,7 +25,7 @@
-
+
diff --git a/components/fpspreadsheet/examples/fpschart/fpschart.ico b/components/fpspreadsheet/examples/fpschart/fpschart.ico
new file mode 100644
index 000000000..0341321b5
Binary files /dev/null and b/components/fpspreadsheet/examples/fpschart/fpschart.ico differ
diff --git a/components/fpspreadsheet/examples/fpschart/fpschart.lpi b/components/fpspreadsheet/examples/fpschart/fpschart.lpi
new file mode 100644
index 000000000..7d8bced85
--- /dev/null
+++ b/components/fpspreadsheet/examples/fpschart/fpschart.lpi
@@ -0,0 +1,98 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/components/fpspreadsheet/examples/fpschart/fpschart.lpr b/components/fpspreadsheet/examples/fpschart/fpschart.lpr
new file mode 100644
index 000000000..a0cd3af67
--- /dev/null
+++ b/components/fpspreadsheet/examples/fpschart/fpschart.lpr
@@ -0,0 +1,21 @@
+program fpschart;
+
+{$mode objfpc}{$H+}
+
+uses
+ {$IFDEF UNIX}{$IFDEF UseCThreads}
+ cthreads,
+ {$ENDIF}{$ENDIF}
+ Interfaces, // this includes the LCL widgetset
+ Forms, tachartlazaruspkg, mainform, laz_fpspreadsheet_visual
+ { you can add units after this };
+
+{$R *.res}
+
+begin
+ Application.Title:='project1';
+ Application.Initialize;
+ Application.CreateForm(TFPSChartForm, FPSChartForm);
+ Application.Run;
+end.
+
diff --git a/components/fpspreadsheet/examples/fpschart/mainform.lfm b/components/fpspreadsheet/examples/fpschart/mainform.lfm
new file mode 100644
index 000000000..89c70905a
--- /dev/null
+++ b/components/fpspreadsheet/examples/fpschart/mainform.lfm
@@ -0,0 +1,62 @@
+object FPSChartForm: TFPSChartForm
+ Left = 179
+ Height = 331
+ Top = 157
+ Width = 742
+ Caption = 'FPSpreadsheet Chart Example'
+ ClientHeight = 331
+ ClientWidth = 742
+ LCLVersion = '0.9.29'
+ object MyChart: TChart
+ Left = 400
+ Height = 240
+ Top = 24
+ Width = 336
+ AxisList = <
+ item
+ Alignment = calLeft
+ Title.Font.Orientation = 900
+ end
+ item
+ Alignment = calBottom
+ end>
+ Foot.Brush.Color = clBtnFace
+ Foot.Font.Color = clBlue
+ Title.Brush.Color = clBtnFace
+ Title.Font.Color = clBlue
+ Title.Text.Strings = (
+ 'TAChart'
+ )
+ ParentColor = False
+ object MyChartLineSeries: TLineSeries
+ LinePen.Color = clRed
+ SeriesColor = clRed
+ Source = FPSChartSource
+ end
+ end
+ object WorksheetGrid: TsWorksheetGrid
+ Left = 16
+ Height = 240
+ Top = 24
+ Width = 360
+ Options = [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine, goRangeSelect, goEditing, goSmoothScroll]
+ TabOrder = 1
+ end
+ object btnCreateGraphic: TButton
+ Left = 104
+ Height = 25
+ Top = 280
+ Width = 128
+ Caption = 'Create Graphic'
+ OnClick = btnCreateGraphicClick
+ TabOrder = 2
+ end
+ object FPSChartSource: TsWorksheetChartSource
+ PointsNumber = 5
+ YFirstCellCol = 1
+ XSelectionDirection = fpsVerticalSelection
+ YSelectionDirection = fpsVerticalSelection
+ left = 376
+ top = 264
+ end
+end
diff --git a/components/fpspreadsheet/examples/fpschart/mainform.pas b/components/fpspreadsheet/examples/fpschart/mainform.pas
new file mode 100644
index 000000000..6b92a64f4
--- /dev/null
+++ b/components/fpspreadsheet/examples/fpschart/mainform.pas
@@ -0,0 +1,43 @@
+unit mainform;
+
+{$mode objfpc}{$H+}
+
+interface
+
+uses
+ Classes, SysUtils, FileUtil, LResources, Forms, Controls, Graphics, Dialogs,
+ StdCtrls, Grids, fpspreadsheetchart, fpspreadsheetgrid, TAGraph, TASeries;
+
+type
+
+ { TFPSChartForm }
+
+ TFPSChartForm = class(TForm)
+ btnCreateGraphic: TButton;
+ MyChart: TChart;
+ FPSChartSource: TsWorksheetChartSource;
+ MyChartLineSeries: TLineSeries;
+ WorksheetGrid: TsWorksheetGrid;
+ procedure btnCreateGraphicClick(Sender: TObject);
+ private
+ { private declarations }
+ public
+ { public declarations }
+ end;
+
+var
+ FPSChartForm: TFPSChartForm;
+
+implementation
+
+{$R *.lfm}
+
+{ TFPSChartForm }
+
+procedure TFPSChartForm.btnCreateGraphicClick(Sender: TObject);
+begin
+ FPSChartSource.LoadFromWorksheetGrid(WorksheetGrid);
+end;
+
+end.
+
diff --git a/components/fpspreadsheet/fpspreadsheet.pas b/components/fpspreadsheet/fpspreadsheet.pas
index 856d0f091..089faaacd 100755
--- a/components/fpspreadsheet/fpspreadsheet.pas
+++ b/components/fpspreadsheet/fpspreadsheet.pas
@@ -115,6 +115,7 @@ type
function GetLastColNumber: Cardinal;
function GetLastRowNumber: Cardinal;
function ReadAsUTF8Text(ARow, ACol: Cardinal): ansistring;
+ function ReadAsNumber(ARow, ACol: Cardinal): Double;
procedure RemoveAllCells;
procedure WriteUTF8Text(ARow, ACol: Cardinal; AText: ansistring);
procedure WriteNumber(ARow, ACol: Cardinal; ANumber: double);
@@ -479,6 +480,40 @@ begin
end;
end;
+function TsWorksheet.ReadAsNumber(ARow, ACol: Cardinal): Double;
+var
+ ACell: PCell;
+ Str: string;
+begin
+ ACell := FindCell(ARow, ACol);
+
+ if ACell = nil then
+ begin
+ Result := 0.0;
+ Exit;
+ end;
+
+ case ACell^.ContentType of
+
+ //cctFormula
+ cctNumber: Result := ACell^.NumberValue;
+ cctUTF8String:
+ begin
+ // The try is necessary to catch errors while converting the string
+ // to a number, an operation which may fail
+ try
+ Str := ACell^.UTF8StringValue;
+ Result := StrToFloat(Str);
+ except
+ Result := 0.0;
+ end;
+ end;
+
+ else
+ Result := 0.0;
+ end;
+end;
+
{@@
Clears the list of Cells and releases their memory.
}
diff --git a/components/fpspreadsheet/fpspreadsheetchart.pas b/components/fpspreadsheet/fpspreadsheetchart.pas
new file mode 100644
index 000000000..d2e020184
--- /dev/null
+++ b/components/fpspreadsheet/fpspreadsheetchart.pas
@@ -0,0 +1,208 @@
+{
+fpspreadsheetgrid.pas
+
+Chart data source designed to work together with TChart from Lazarus to display the data
+and with TsWorksheetGrid from FPSpreadsheet to load data from a grid.
+
+AUTHORS: Felipe Monteiro de Carvalho
+}
+unit fpspreadsheetchart;
+
+{$mode objfpc}{$H+}
+
+interface
+
+uses
+ Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs, Grids,
+ // TChart
+ tasources,
+ // FPSpreadsheet Visual
+ fpspreadsheetgrid,
+ // FPSpreadsheet
+ fpspreadsheet;
+
+type
+
+ TsSelectionDirection = (fpsVerticalSelection, fpsHorizontalSelection);
+
+ {@@ Chart data source designed to work together with TChart from Lazarus
+ to display the data.
+
+ The data can be loaded from a TsWorksheetGrid Grid component or
+ directly from a TsWorksheet FPSpreadsheet Worksheet }
+
+ { TsWorksheetChartSource }
+
+ TsWorksheetChartSource = class(TCustomChartSource)
+ private
+ FInternalWorksheet: TsWorksheet;
+ FPointsNumber: Integer;
+ FXSelectionDirection: TsSelectionDirection;
+ FYSelectionDirection: TsSelectionDirection;
+// FWorksheetGrid: TsWorksheetGrid;
+ FXFirstCellCol: Integer;
+ FXFirstCellRow: Integer;
+ FYFirstCellCol: Integer;
+ FYFirstCellRow: Integer;
+ procedure SetPointsNumber(const AValue: Integer);
+ procedure SetXSelectionDirection(const AValue: TsSelectionDirection);
+ procedure SetYSelectionDirection(const AValue: TsSelectionDirection);
+ procedure SetXFirstCellCol(const AValue: Integer);
+ procedure SetXFirstCellRow(const AValue: Integer);
+ procedure SetYFirstCellCol(const AValue: Integer);
+ procedure SetYFirstCellRow(const AValue: Integer);
+ protected
+ FDataWorksheet: TsWorksheet;
+ FCurItem: TChartDataItem;
+ function GetCount: Integer; override;
+ function GetItem(AIndex: Integer): PChartDataItem; override;
+ public
+ constructor Create(AOwner: TComponent); override;
+ destructor Destroy; override;
+ procedure LoadFromWorksheetGrid(const AValue: TsWorksheetGrid);
+ public
+ published
+// property WorksheetGrid: TsWorksheetGrid read FWorksheetGrid write SetWorksheetGrid;
+ property PointsNumber: Integer read FPointsNumber write SetPointsNumber default 0;
+ property XFirstCellCol: Integer read FXFirstCellCol write SetXFirstCellCol default 0;
+ property XFirstCellRow: Integer read FXFirstCellRow write SetXFirstCellRow default 0;
+ property YFirstCellCol: Integer read FYFirstCellCol write SetYFirstCellCol default 0;
+ property YFirstCellRow: Integer read FYFirstCellRow write SetYFirstCellRow default 0;
+ property XSelectionDirection: TsSelectionDirection read FXSelectionDirection write SetXSelectionDirection;
+ property YSelectionDirection: TsSelectionDirection read FYSelectionDirection write SetYSelectionDirection;
+ end;
+
+procedure Register;
+
+implementation
+
+procedure Register;
+begin
+ RegisterComponents('Chart',[TsWorksheetChartSource]);
+end;
+
+{ TsWorksheetChartSource }
+
+procedure TsWorksheetChartSource.SetPointsNumber(const AValue: Integer);
+begin
+ if FPointsNumber = AValue then exit;
+ FPointsNumber := AValue;
+ InvalidateCaches;
+ Notify;
+end;
+
+procedure TsWorksheetChartSource.SetXSelectionDirection(
+ const AValue: TsSelectionDirection);
+begin
+ if FXSelectionDirection=AValue then exit;
+ FXSelectionDirection:=AValue;
+ InvalidateCaches;
+ Notify;
+end;
+
+procedure TsWorksheetChartSource.SetYSelectionDirection(
+ const AValue: TsSelectionDirection);
+begin
+ if FYSelectionDirection=AValue then exit;
+ FYSelectionDirection:=AValue;
+ InvalidateCaches;
+ Notify;
+end;
+
+procedure TsWorksheetChartSource.SetXFirstCellCol(const AValue: Integer);
+begin
+ if FXFirstCellCol=AValue then exit;
+ FXFirstCellCol:=AValue;
+ InvalidateCaches;
+ Notify;
+end;
+
+procedure TsWorksheetChartSource.SetXFirstCellRow(const AValue: Integer);
+begin
+ if FXFirstCellRow=AValue then exit;
+ FXFirstCellRow:=AValue;
+ InvalidateCaches;
+ Notify;
+end;
+
+procedure TsWorksheetChartSource.SetYFirstCellCol(const AValue: Integer);
+begin
+ if FYFirstCellCol=AValue then exit;
+ FYFirstCellCol:=AValue;
+ InvalidateCaches;
+ Notify;
+end;
+
+procedure TsWorksheetChartSource.SetYFirstCellRow(const AValue: Integer);
+begin
+ if FYFirstCellRow=AValue then exit;
+ FYFirstCellRow:=AValue;
+ InvalidateCaches;
+ Notify;
+end;
+
+function TsWorksheetChartSource.GetCount: Integer;
+begin
+ Result := FPointsNumber;
+end;
+
+function TsWorksheetChartSource.GetItem(AIndex: Integer): PChartDataItem;
+var
+ XRow, XCol, YRow, YCol: Integer;
+begin
+ // First calculate the cell position
+ if XSelectionDirection = fpsVerticalSelection then
+ begin
+ XRow := FXFirstCellRow + AIndex;
+ XCol := FXFirstCellCol;
+ end
+ else
+ begin
+ XRow := FXFirstCellRow;
+ XCol := FXFirstCellCol + AIndex;
+ end;
+
+ if YSelectionDirection = fpsVerticalSelection then
+ begin
+ YRow := FYFirstCellRow + AIndex;
+ YCol := FYFirstCellCol;
+ end
+ else
+ begin
+ YRow := FYFirstCellRow;
+ YCol := FYFirstCellCol + AIndex;
+ end;
+
+ // Check the corresponding cell, if it is empty, use zero
+ // If not, then get a number value
+
+ FCurItem.X := FDataWorksheet.ReadAsNumber(XRow, XCol);
+ FCurItem.Y := FDataWorksheet.ReadAsNumber(YRow, YCol);
+
+ Result := @FCurItem;
+end;
+
+constructor TsWorksheetChartSource.Create(AOwner: TComponent);
+begin
+ inherited Create(AOwner);
+ FInternalWorksheet := TsWorksheet.Create;
+ FDataWorksheet := FInternalWorksheet;
+end;
+
+destructor TsWorksheetChartSource.Destroy;
+begin
+ if FInternalWorksheet <> nil then FInternalWorksheet.Free;
+ inherited Destroy;
+end;
+
+procedure TsWorksheetChartSource.LoadFromWorksheetGrid(const AValue: TsWorksheetGrid);
+begin
+ if AValue = nil then Exit;
+
+ AValue.SaveToWorksheet(FDataWorksheet);
+
+ InvalidateCaches;
+ Notify;
+end;
+
+end.
diff --git a/components/fpspreadsheet/fpspreadsheetgrid.pas b/components/fpspreadsheet/fpspreadsheetgrid.pas
index 73c1fd602..ba72a9ea8 100644
--- a/components/fpspreadsheet/fpspreadsheetgrid.pas
+++ b/components/fpspreadsheet/fpspreadsheetgrid.pas
@@ -1,3 +1,10 @@
+{
+fpspreadsheetgrid.pas
+
+Grid component which can load and write data from / to FPSpreadsheet documents
+
+AUTHORS: Felipe Monteiro de Carvalho
+}
unit fpspreadsheetgrid;
{$mode objfpc}{$H+}
@@ -10,14 +17,12 @@ uses
type
- { TsWorksheetGrid }
-
{ TsCustomWorksheetGrid }
TsCustomWorksheetGrid = class(TCustomStringGrid)
private
- FDisplayFixedColRow: Boolean;
FWorksheet: TsWorksheet;
+ FDisplayFixedColRow: Boolean;
procedure SetDisplayFixedColRow(const AValue: Boolean);
{ Private declarations }
protected
@@ -26,9 +31,12 @@ type
{ methods }
constructor Create(AOwner: TComponent); override;
procedure LoadFromWorksheet(AWorksheet: TsWorksheet);
+ procedure SaveToWorksheet(AWorksheet: TsWorksheet);
property DisplayFixedColRow: Boolean read FDisplayFixedColRow write SetDisplayFixedColRow;
end;
+ { TsWorksheetGrid }
+
TsWorksheetGrid = class(TsCustomWorksheetGrid)
published
property Align;
@@ -135,6 +143,10 @@ begin
RegisterComponents('Additional',[TsWorksheetGrid]);
end;
+const
+ INT_FPSCOLROW_TO_GRIDCOLROW_WITH_FIXEDCOLROW = 2;
+ INT_FPSCOLROW_TO_GRIDCOLROW = 1;
+
{ TsCustomWorksheetGrid }
procedure TsCustomWorksheetGrid.SetDisplayFixedColRow(const AValue: Boolean);
@@ -181,13 +193,13 @@ begin
begin
if DisplayFixedColRow then
begin
- ColCount := FWorksheet.GetLastColNumber() + 2;
- RowCount := FWorksheet.GetLastRowNumber() + 2;
+ ColCount := FWorksheet.GetLastColNumber() + INT_FPSCOLROW_TO_GRIDCOLROW_WITH_FIXEDCOLROW;
+ RowCount := FWorksheet.GetLastRowNumber() + INT_FPSCOLROW_TO_GRIDCOLROW_WITH_FIXEDCOLROW;
end
else
begin
- ColCount := FWorksheet.GetLastColNumber() + 1;
- RowCount := FWorksheet.GetLastRowNumber() + 1;
+ ColCount := FWorksheet.GetLastColNumber() + INT_FPSCOLROW_TO_GRIDCOLROW;
+ RowCount := FWorksheet.GetLastRowNumber() + INT_FPSCOLROW_TO_GRIDCOLROW;
end;
end;
@@ -209,4 +221,21 @@ begin
end;
end;
+procedure TsCustomWorksheetGrid.SaveToWorksheet(AWorksheet: TsWorksheet);
+var
+ x, y: Integer;
+ Str: string;
+begin
+ if AWorksheet = nil then Exit;
+
+ { Copy the contents }
+
+ for x := 0 to ColCount - 1 do
+ for y := 0 to RowCount - 1 do
+ begin
+ Str := GetCells(x, y);
+ if Str <> '' then AWorksheet.WriteUTF8Text(y, x, Str);
+ end;
+end;
+
end.
diff --git a/components/fpspreadsheet/laz_fpspreadsheet_visual.lpk b/components/fpspreadsheet/laz_fpspreadsheet_visual.lpk
index d6031afa5..92607bb4a 100644
--- a/components/fpspreadsheet/laz_fpspreadsheet_visual.lpk
+++ b/components/fpspreadsheet/laz_fpspreadsheet_visual.lpk
@@ -7,31 +7,39 @@
-
+
-
+
+
+
+
+
+
-
+
-
+
-
+
+
+
+
-
+
diff --git a/components/fpspreadsheet/laz_fpspreadsheet_visual.pas b/components/fpspreadsheet/laz_fpspreadsheet_visual.pas
index 10a9c2828..e9e076bbc 100644
--- a/components/fpspreadsheet/laz_fpspreadsheet_visual.pas
+++ b/components/fpspreadsheet/laz_fpspreadsheet_visual.pas
@@ -1,4 +1,4 @@
-{ This file was automatically created by Lazarus. do not edit!
+{ This file was automatically created by Lazarus. Do not edit!
This source is only used to compile and install the package.
}
@@ -7,13 +7,14 @@ unit laz_fpspreadsheet_visual;
interface
uses
- fpspreadsheetgrid, LazarusPackageIntf;
+ fpspreadsheetgrid, fpspreadsheetchart, LazarusPackageIntf;
implementation
procedure Register;
begin
RegisterUnit('fpspreadsheetgrid', @fpspreadsheetgrid.Register);
+ RegisterUnit('fpspreadsheetchart', @fpspreadsheetchart.Register);
end;
initialization