Implements a charting component for FPSpreadsheet

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@1209 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
sekelsenmat
2010-05-01 18:10:38 +00:00
parent beaa987f53
commit f9a882cc87
11 changed files with 522 additions and 17 deletions

View File

@ -14,7 +14,7 @@
<UseXPManifest Value="True"/> <UseXPManifest Value="True"/>
</General> </General>
<VersionInfo> <VersionInfo>
<ProjectVersion Value=""/> <StringTable Comments="" CompanyName="" FileDescription="" FileVersion="0.0.0.0" InternalName="" LegalCopyright="" LegalTrademarks="" OriginalFilename="" ProductName="" ProductVersion=""/>
</VersionInfo> </VersionInfo>
<PublishOptions> <PublishOptions>
<Version Value="2"/> <Version Value="2"/>
@ -25,7 +25,7 @@
<RunParams> <RunParams>
<local> <local>
<FormatVersion Value="1"/> <FormatVersion Value="1"/>
<LaunchingApplication PathPlusParams="/usr/X11R6/bin/xterm -T 'Lazarus Run Output' -e $(LazarusDir)/tools/runwait.sh $(TargetCmdLine)"/> <LaunchingApplication PathPlusParams="\usr\X11R6\bin\xterm -T 'Lazarus Run Output' -e $(LazarusDir)\tools\runwait.sh $(TargetCmdLine)"/>
</local> </local>
</RunParams> </RunParams>
<RequiredPackages Count="1"> <RequiredPackages Count="1">

Binary file not shown.

After

Width:  |  Height:  |  Size: 134 KiB

View File

@ -0,0 +1,98 @@
<?xml version="1.0"?>
<CONFIG>
<ProjectOptions>
<Version Value="7"/>
<General>
<Flags>
<UseDefaultCompilerOptions Value="True"/>
</Flags>
<SessionStorage Value="InProjectDir"/>
<MainUnit Value="0"/>
<TargetFileExt Value=""/>
<ResourceType Value="res"/>
<UseXPManifest Value="True"/>
<Icon Value="0"/>
</General>
<VersionInfo>
<Language Value=""/>
<CharSet Value=""/>
<StringTable Comments="" CompanyName="" FileDescription="" FileVersion="" InternalName="" LegalCopyright="" LegalTrademarks="" OriginalFilename="" ProductName="" ProductVersion=""/>
</VersionInfo>
<PublishOptions>
<Version Value="2"/>
<IgnoreBinaries Value="False"/>
<IncludeFileFilter Value="*.(pas|pp|inc|lfm|lpr|lrs|lpi|lpk|sh|xml)"/>
<ExcludeFileFilter Value="*.(bak|ppu|ppw|o|so);*~;backup"/>
</PublishOptions>
<RunParams>
<local>
<FormatVersion Value="1"/>
<LaunchingApplication PathPlusParams="/usr/X11R6/bin/xterm -T 'Lazarus Run Output' -e $(LazarusDir)/tools/runwait.sh $(TargetCmdLine)"/>
</local>
</RunParams>
<RequiredPackages Count="3">
<Item1>
<PackageName Value="TAChartLazarusPkg"/>
<MinVersion Major="1" Valid="True"/>
</Item1>
<Item2>
<PackageName Value="laz_fpspreadsheet_visual"/>
</Item2>
<Item3>
<PackageName Value="LCL"/>
</Item3>
</RequiredPackages>
<Units Count="2">
<Unit0>
<Filename Value="fpschart.lpr"/>
<IsPartOfProject Value="True"/>
<UnitName Value="fpschart"/>
</Unit0>
<Unit1>
<Filename Value="mainform.pas"/>
<IsPartOfProject Value="True"/>
<ComponentName Value="FPSChartForm"/>
<ResourceBaseClass Value="Form"/>
<UnitName Value="mainform"/>
</Unit1>
</Units>
</ProjectOptions>
<CompilerOptions>
<Version Value="8"/>
<Target>
<Filename Value="fpschart"/>
</Target>
<SearchPaths>
<IncludeFiles Value="$(ProjOutDir)/"/>
<UnitOutputDirectory Value="lib/$(TargetCPU)-$(TargetOS)"/>
</SearchPaths>
<Parsing>
<SyntaxOptions>
<UseAnsiStrings Value="True"/>
</SyntaxOptions>
</Parsing>
<Linking>
<Options>
<Win32>
<GraphicApplication Value="True"/>
</Win32>
</Options>
</Linking>
<Other>
<CompilerPath Value="$(CompPath)"/>
</Other>
</CompilerOptions>
<Debugging>
<Exceptions Count="3">
<Item1>
<Name Value="EAbort"/>
</Item1>
<Item2>
<Name Value="ECodetoolError"/>
</Item2>
<Item3>
<Name Value="EFOpenError"/>
</Item3>
</Exceptions>
</Debugging>
</CONFIG>

View File

@ -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.

View File

@ -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

View File

@ -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.

View File

@ -115,6 +115,7 @@ type
function GetLastColNumber: Cardinal; function GetLastColNumber: Cardinal;
function GetLastRowNumber: Cardinal; function GetLastRowNumber: Cardinal;
function ReadAsUTF8Text(ARow, ACol: Cardinal): ansistring; function ReadAsUTF8Text(ARow, ACol: Cardinal): ansistring;
function ReadAsNumber(ARow, ACol: Cardinal): Double;
procedure RemoveAllCells; procedure RemoveAllCells;
procedure WriteUTF8Text(ARow, ACol: Cardinal; AText: ansistring); procedure WriteUTF8Text(ARow, ACol: Cardinal; AText: ansistring);
procedure WriteNumber(ARow, ACol: Cardinal; ANumber: double); procedure WriteNumber(ARow, ACol: Cardinal; ANumber: double);
@ -479,6 +480,40 @@ begin
end; end;
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. Clears the list of Cells and releases their memory.
} }

View File

@ -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.

View File

@ -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; unit fpspreadsheetgrid;
{$mode objfpc}{$H+} {$mode objfpc}{$H+}
@ -10,14 +17,12 @@ uses
type type
{ TsWorksheetGrid }
{ TsCustomWorksheetGrid } { TsCustomWorksheetGrid }
TsCustomWorksheetGrid = class(TCustomStringGrid) TsCustomWorksheetGrid = class(TCustomStringGrid)
private private
FDisplayFixedColRow: Boolean;
FWorksheet: TsWorksheet; FWorksheet: TsWorksheet;
FDisplayFixedColRow: Boolean;
procedure SetDisplayFixedColRow(const AValue: Boolean); procedure SetDisplayFixedColRow(const AValue: Boolean);
{ Private declarations } { Private declarations }
protected protected
@ -26,9 +31,12 @@ type
{ methods } { methods }
constructor Create(AOwner: TComponent); override; constructor Create(AOwner: TComponent); override;
procedure LoadFromWorksheet(AWorksheet: TsWorksheet); procedure LoadFromWorksheet(AWorksheet: TsWorksheet);
procedure SaveToWorksheet(AWorksheet: TsWorksheet);
property DisplayFixedColRow: Boolean read FDisplayFixedColRow write SetDisplayFixedColRow; property DisplayFixedColRow: Boolean read FDisplayFixedColRow write SetDisplayFixedColRow;
end; end;
{ TsWorksheetGrid }
TsWorksheetGrid = class(TsCustomWorksheetGrid) TsWorksheetGrid = class(TsCustomWorksheetGrid)
published published
property Align; property Align;
@ -135,6 +143,10 @@ begin
RegisterComponents('Additional',[TsWorksheetGrid]); RegisterComponents('Additional',[TsWorksheetGrid]);
end; end;
const
INT_FPSCOLROW_TO_GRIDCOLROW_WITH_FIXEDCOLROW = 2;
INT_FPSCOLROW_TO_GRIDCOLROW = 1;
{ TsCustomWorksheetGrid } { TsCustomWorksheetGrid }
procedure TsCustomWorksheetGrid.SetDisplayFixedColRow(const AValue: Boolean); procedure TsCustomWorksheetGrid.SetDisplayFixedColRow(const AValue: Boolean);
@ -181,13 +193,13 @@ begin
begin begin
if DisplayFixedColRow then if DisplayFixedColRow then
begin begin
ColCount := FWorksheet.GetLastColNumber() + 2; ColCount := FWorksheet.GetLastColNumber() + INT_FPSCOLROW_TO_GRIDCOLROW_WITH_FIXEDCOLROW;
RowCount := FWorksheet.GetLastRowNumber() + 2; RowCount := FWorksheet.GetLastRowNumber() + INT_FPSCOLROW_TO_GRIDCOLROW_WITH_FIXEDCOLROW;
end end
else else
begin begin
ColCount := FWorksheet.GetLastColNumber() + 1; ColCount := FWorksheet.GetLastColNumber() + INT_FPSCOLROW_TO_GRIDCOLROW;
RowCount := FWorksheet.GetLastRowNumber() + 1; RowCount := FWorksheet.GetLastRowNumber() + INT_FPSCOLROW_TO_GRIDCOLROW;
end; end;
end; end;
@ -209,4 +221,21 @@ begin
end; end;
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. end.

View File

@ -7,31 +7,39 @@
<Version Value="8"/> <Version Value="8"/>
<PathDelim Value="\"/> <PathDelim Value="\"/>
<SearchPaths> <SearchPaths>
<UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)\"/> <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/>
</SearchPaths> </SearchPaths>
<Other> <Other>
<CompilerPath Value="$(CompPath)"/> <CompilerPath Value="$(CompPath)"/>
</Other> </Other>
</CompilerOptions> </CompilerOptions>
<Files Count="1"> <Files Count="2">
<Item1> <Item1>
<Filename Value="fpspreadsheetgrid.pas"/> <Filename Value="fpspreadsheetgrid.pas"/>
<HasRegisterProc Value="True"/> <HasRegisterProc Value="True"/>
<UnitName Value="FPSpreadsheetGrid"/> <UnitName Value="FPSpreadsheetGrid"/>
</Item1> </Item1>
<Item2>
<Filename Value="fpspreadsheetchart.pas"/>
<HasRegisterProc Value="True"/>
<UnitName Value="fpspreadsheetchart"/>
</Item2>
</Files> </Files>
<Type Value="RunAndDesignTime"/> <Type Value="RunAndDesignTime"/>
<RequiredPkgs Count="3"> <RequiredPkgs Count="4">
<Item1> <Item1>
<PackageName Value="laz_fpspreadsheet"/> <PackageName Value="tachartlazaruspkg"/>
</Item1> </Item1>
<Item2> <Item2>
<PackageName Value="LCL"/> <PackageName Value="laz_fpspreadsheet"/>
</Item2> </Item2>
<Item3> <Item3>
<PackageName Value="LCL"/>
</Item3>
<Item4>
<PackageName Value="FCL"/> <PackageName Value="FCL"/>
<MinVersion Major="1" Valid="True"/> <MinVersion Major="1" Valid="True"/>
</Item3> </Item4>
</RequiredPkgs> </RequiredPkgs>
<UsageOptions> <UsageOptions>
<UnitPath Value="$(PkgOutDir)"/> <UnitPath Value="$(PkgOutDir)"/>

View File

@ -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. This source is only used to compile and install the package.
} }
@ -7,13 +7,14 @@ unit laz_fpspreadsheet_visual;
interface interface
uses uses
fpspreadsheetgrid, LazarusPackageIntf; fpspreadsheetgrid, fpspreadsheetchart, LazarusPackageIntf;
implementation implementation
procedure Register; procedure Register;
begin begin
RegisterUnit('fpspreadsheetgrid', @fpspreadsheetgrid.Register); RegisterUnit('fpspreadsheetgrid', @fpspreadsheetgrid.Register);
RegisterUnit('fpspreadsheetchart', @fpspreadsheetchart.Register);
end; end;
initialization initialization