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