You've already forked lazarus-ccr
fpspreadsheet: Extended chart display demo. Rework TsWorkbookSource's ListenerNotification to avoid crash when chart destroy a listening chartsource. Chart link can display pie series now.
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@9053 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
@ -65,6 +65,7 @@
|
|||||||
<Linking>
|
<Linking>
|
||||||
<Debugging>
|
<Debugging>
|
||||||
<DebugInfoType Value="dsDwarf3"/>
|
<DebugInfoType Value="dsDwarf3"/>
|
||||||
|
<UseHeaptrc Value="True"/>
|
||||||
</Debugging>
|
</Debugging>
|
||||||
<Options>
|
<Options>
|
||||||
<Win32>
|
<Win32>
|
||||||
|
@ -10,8 +10,8 @@ object Form1: TForm1
|
|||||||
OnCreate = FormCreate
|
OnCreate = FormCreate
|
||||||
object sWorksheetGrid1: TsWorksheetGrid
|
object sWorksheetGrid1: TsWorksheetGrid
|
||||||
Left = 0
|
Left = 0
|
||||||
Height = 527
|
Height = 489
|
||||||
Top = 0
|
Top = 38
|
||||||
Width = 402
|
Width = 402
|
||||||
FrozenCols = 0
|
FrozenCols = 0
|
||||||
FrozenRows = 0
|
FrozenRows = 0
|
||||||
@ -28,14 +28,14 @@ object Form1: TForm1
|
|||||||
end
|
end
|
||||||
object Splitter1: TSplitter
|
object Splitter1: TSplitter
|
||||||
Left = 402
|
Left = 402
|
||||||
Height = 527
|
Height = 489
|
||||||
Top = 0
|
Top = 38
|
||||||
Width = 5
|
Width = 5
|
||||||
end
|
end
|
||||||
object Chart1: TChart
|
object Chart1: TChart
|
||||||
Left = 407
|
Left = 407
|
||||||
Height = 527
|
Height = 489
|
||||||
Top = 0
|
Top = 38
|
||||||
Width = 694
|
Width = 694
|
||||||
AxisList = <
|
AxisList = <
|
||||||
item
|
item
|
||||||
@ -55,10 +55,96 @@ object Form1: TForm1
|
|||||||
)
|
)
|
||||||
Align = alClient
|
Align = alClient
|
||||||
end
|
end
|
||||||
|
object Panel1: TPanel
|
||||||
|
Left = 0
|
||||||
|
Height = 38
|
||||||
|
Top = 0
|
||||||
|
Width = 1101
|
||||||
|
Align = alTop
|
||||||
|
AutoSize = True
|
||||||
|
BevelOuter = bvNone
|
||||||
|
ClientHeight = 38
|
||||||
|
ClientWidth = 1101
|
||||||
|
TabOrder = 3
|
||||||
|
object Label1: TLabel
|
||||||
|
AnchorSideLeft.Control = Panel1
|
||||||
|
AnchorSideTop.Control = Panel1
|
||||||
|
AnchorSideTop.Side = asrCenter
|
||||||
|
Left = 6
|
||||||
|
Height = 15
|
||||||
|
Top = 12
|
||||||
|
Width = 51
|
||||||
|
BorderSpacing.Around = 6
|
||||||
|
Caption = 'File name'
|
||||||
|
end
|
||||||
|
object ComboBox1: TComboBox
|
||||||
|
AnchorSideLeft.Control = Label1
|
||||||
|
AnchorSideLeft.Side = asrBottom
|
||||||
|
AnchorSideTop.Control = Panel1
|
||||||
|
AnchorSideTop.Side = asrCenter
|
||||||
|
AnchorSideRight.Control = Button1
|
||||||
|
Left = 63
|
||||||
|
Height = 23
|
||||||
|
Top = 8
|
||||||
|
Width = 911
|
||||||
|
Anchors = [akTop, akLeft, akRight]
|
||||||
|
BorderSpacing.Around = 6
|
||||||
|
ItemHeight = 15
|
||||||
|
Items.Strings = (
|
||||||
|
'../../../other/chart/area.ods'
|
||||||
|
'../../../other/chart/bars.ods'
|
||||||
|
'../../../other/chart/bubble.ods'
|
||||||
|
'../../../other/chart/pie.ods'
|
||||||
|
'../../../other/chart/radar.ods'
|
||||||
|
'../../../other/chart/regression.ods'
|
||||||
|
)
|
||||||
|
TabOrder = 0
|
||||||
|
TextHint = 'Enter or select file name'
|
||||||
|
OnCloseUp = ComboBox1CloseUp
|
||||||
|
end
|
||||||
|
object Button1: TButton
|
||||||
|
AnchorSideTop.Control = Panel1
|
||||||
|
AnchorSideTop.Side = asrCenter
|
||||||
|
AnchorSideRight.Control = Button2
|
||||||
|
Left = 980
|
||||||
|
Height = 25
|
||||||
|
Top = 7
|
||||||
|
Width = 35
|
||||||
|
Anchors = [akTop, akRight]
|
||||||
|
AutoSize = True
|
||||||
|
BorderSpacing.Around = 6
|
||||||
|
Caption = '...'
|
||||||
|
TabOrder = 1
|
||||||
|
OnClick = Button1Click
|
||||||
|
end
|
||||||
|
object Button2: TButton
|
||||||
|
AnchorSideTop.Control = Panel1
|
||||||
|
AnchorSideTop.Side = asrCenter
|
||||||
|
AnchorSideRight.Control = Panel1
|
||||||
|
AnchorSideRight.Side = asrBottom
|
||||||
|
Left = 1021
|
||||||
|
Height = 25
|
||||||
|
Top = 7
|
||||||
|
Width = 74
|
||||||
|
Anchors = [akTop, akRight]
|
||||||
|
AutoSize = True
|
||||||
|
BorderSpacing.Around = 6
|
||||||
|
Caption = 'Open file'
|
||||||
|
TabOrder = 2
|
||||||
|
OnClick = Button2Click
|
||||||
|
end
|
||||||
|
end
|
||||||
object sWorkbookSource1: TsWorkbookSource
|
object sWorkbookSource1: TsWorkbookSource
|
||||||
FileFormat = sfUser
|
FileFormat = sfUser
|
||||||
Options = []
|
Options = []
|
||||||
Left = 244
|
Left = 244
|
||||||
Top = 138
|
Top = 138
|
||||||
end
|
end
|
||||||
|
object OpenDialog1: TOpenDialog
|
||||||
|
DefaultExt = '.ods'
|
||||||
|
Filter = 'OpenDocument Spreadsheet Files|*.ods'
|
||||||
|
Options = [ofFileMustExist, ofEnableSizing, ofViewDetail]
|
||||||
|
Left = 976
|
||||||
|
Top = 56
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
@ -5,7 +5,7 @@ unit main;
|
|||||||
interface
|
interface
|
||||||
|
|
||||||
uses
|
uses
|
||||||
Classes, SysUtils, Forms, Controls, Graphics, Dialogs, ExtCtrls,
|
Classes, SysUtils, Forms, Controls, Graphics, Dialogs, ExtCtrls, StdCtrls,
|
||||||
TAGraph,
|
TAGraph,
|
||||||
fpSpreadsheet, fpsTypes, fpsOpenDocument,
|
fpSpreadsheet, fpsTypes, fpsOpenDocument,
|
||||||
fpSpreadsheetCtrls, fpSpreadsheetGrid, fpSpreadsheetChart;
|
fpSpreadsheetCtrls, fpSpreadsheetGrid, fpSpreadsheetChart;
|
||||||
@ -15,13 +15,24 @@ type
|
|||||||
{ TForm1 }
|
{ TForm1 }
|
||||||
|
|
||||||
TForm1 = class(TForm)
|
TForm1 = class(TForm)
|
||||||
|
Button1: TButton;
|
||||||
|
Button2: TButton;
|
||||||
Chart1: TChart;
|
Chart1: TChart;
|
||||||
|
ComboBox1: TComboBox;
|
||||||
|
Label1: TLabel;
|
||||||
|
OpenDialog1: TOpenDialog;
|
||||||
|
Panel1: TPanel;
|
||||||
Splitter1: TSplitter;
|
Splitter1: TSplitter;
|
||||||
sWorkbookSource1: TsWorkbookSource;
|
sWorkbookSource1: TsWorkbookSource;
|
||||||
sWorksheetGrid1: TsWorksheetGrid;
|
sWorksheetGrid1: TsWorksheetGrid;
|
||||||
|
procedure Button1Click(Sender: TObject);
|
||||||
|
procedure Button2Click(Sender: TObject);
|
||||||
|
procedure ComboBox1CloseUp(Sender: TObject);
|
||||||
procedure FormCreate(Sender: TObject);
|
procedure FormCreate(Sender: TObject);
|
||||||
private
|
private
|
||||||
sChartLink: TsWorkbookChartLink;
|
sChartLink: TsWorkbookChartLink;
|
||||||
|
FFileName: String;
|
||||||
|
procedure LoadFile(AFileName: String);
|
||||||
|
|
||||||
public
|
public
|
||||||
|
|
||||||
@ -46,11 +57,47 @@ const
|
|||||||
|
|
||||||
{ TForm1 }
|
{ TForm1 }
|
||||||
|
|
||||||
|
procedure TForm1.Button1Click(Sender: TObject);
|
||||||
|
begin
|
||||||
|
OpenDialog1.InitialDir := ExtractFilePath(Combobox1.Text);
|
||||||
|
OpenDialog1.FileName := '';
|
||||||
|
if OpenDialog1.Execute then
|
||||||
|
begin
|
||||||
|
Combobox1.Text := OpenDialog1.FileName;
|
||||||
|
LoadFile(OpenDialog1.FileName);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TForm1.Button2Click(Sender: TObject);
|
||||||
|
begin
|
||||||
|
LoadFile(Combobox1.Text);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TForm1.ComboBox1CloseUp(Sender: TObject);
|
||||||
|
begin
|
||||||
|
Combobox1.Text := Combobox1.Items[Combobox1.ItemIndex];
|
||||||
|
LoadFile(Combobox1.Text);
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TForm1.FormCreate(Sender: TObject);
|
procedure TForm1.FormCreate(Sender: TObject);
|
||||||
|
begin
|
||||||
|
if ParamCount > 0 then
|
||||||
|
begin
|
||||||
|
Combobox1.Text := ParamStr(1);
|
||||||
|
LoadFile(Combobox1.Text);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TForm1.LoadFile(AFileName: String);
|
||||||
var
|
var
|
||||||
fn: String;
|
fn: String;
|
||||||
begin
|
begin
|
||||||
fn := ExpandFileName(FILE_NAME);
|
fn := ExpandFileName(AFileName);
|
||||||
|
if not FileExists(fn) then
|
||||||
|
begin
|
||||||
|
MessageDlg('File "' + fn + '" not found.', mtError, [mbOK], 0);
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
|
||||||
sWorkbookSource1.FileFormat := sfOpenDocument;
|
sWorkbookSource1.FileFormat := sfOpenDocument;
|
||||||
if FileExists(fn) then
|
if FileExists(fn) then
|
||||||
@ -61,6 +108,5 @@ begin
|
|||||||
sChartLink.WorkbookSource := sWorkbookSource1;
|
sChartLink.WorkbookSource := sWorkbookSource1;
|
||||||
sChartLink.WorkbookChartIndex := 0;
|
sChartLink.WorkbookChartIndex := 0;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
@ -390,24 +390,12 @@ type
|
|||||||
constructor Create(AChart: TsChart); override;
|
constructor Create(AChart: TsChart); override;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
TsBubbleSeries = class(TsChartSeries)
|
|
||||||
// to do: inherited from ScatterSeries, but without symbols
|
|
||||||
private
|
|
||||||
FBubbleRange: TsChartRange;
|
|
||||||
public
|
|
||||||
constructor Create(AChart: TsChart); override;
|
|
||||||
destructor Destroy; override;
|
|
||||||
procedure SetBubbleRange(ARow1, ACol1, ARow2, ACol2: Cardinal);
|
|
||||||
procedure SetBubbleRange(ASheet1: String; ARow1, ACol1: Cardinal; ASheet2: String; ARow2, ACol2: Cardinal);
|
|
||||||
property BubbleRange: TsChartRange read FBubbleRange;
|
|
||||||
end;
|
|
||||||
|
|
||||||
TsChartSeriesSymbol = (
|
TsChartSeriesSymbol = (
|
||||||
cssRect, cssDiamond, cssTriangle, cssTriangleDown, cssTriangleLeft,
|
cssRect, cssDiamond, cssTriangle, cssTriangleDown, cssTriangleLeft,
|
||||||
cssTriangleRight, cssCircle, cssStar, cssX, cssPlus, cssAsterisk
|
cssTriangleRight, cssCircle, cssStar, cssX, cssPlus, cssAsterisk
|
||||||
);
|
);
|
||||||
|
|
||||||
TsLineSeries = class(TsChartSeries)
|
TsCustomLineSeries = class(TsChartSeries)
|
||||||
private
|
private
|
||||||
FSymbol: TsChartSeriesSymbol;
|
FSymbol: TsChartSeriesSymbol;
|
||||||
FSymbolHeight: Double; // in mm
|
FSymbolHeight: Double; // in mm
|
||||||
@ -417,9 +405,7 @@ type
|
|||||||
FBorder: TsChartLine;
|
FBorder: TsChartLine;
|
||||||
function GetSymbolFill: TsChartFill;
|
function GetSymbolFill: TsChartFill;
|
||||||
procedure SetSymbolFill(Value: TsChartFill);
|
procedure SetSymbolFill(Value: TsChartFill);
|
||||||
public
|
protected
|
||||||
constructor Create(AChart: TsChart); override;
|
|
||||||
destructor Destroy; override;
|
|
||||||
property Symbol: TsChartSeriesSymbol read FSymbol write FSymbol;
|
property Symbol: TsChartSeriesSymbol read FSymbol write FSymbol;
|
||||||
property SymbolBorder: TsChartLine read FBorder write FBorder;
|
property SymbolBorder: TsChartLine read FBorder write FBorder;
|
||||||
property SymbolFill: TsChartFill read GetSymbolFill write SetSymbolFill;
|
property SymbolFill: TsChartFill read GetSymbolFill write SetSymbolFill;
|
||||||
@ -427,6 +413,20 @@ type
|
|||||||
property SymbolWidth: double read FSymbolWidth write FSymbolWidth;
|
property SymbolWidth: double read FSymbolWidth write FSymbolWidth;
|
||||||
property ShowLines: Boolean read FShowLines write FShowLines;
|
property ShowLines: Boolean read FShowLines write FShowLines;
|
||||||
property ShowSymbols: Boolean read FShowSymbols write FShowSymbols;
|
property ShowSymbols: Boolean read FShowSymbols write FShowSymbols;
|
||||||
|
public
|
||||||
|
constructor Create(AChart: TsChart); override;
|
||||||
|
destructor Destroy; override;
|
||||||
|
end;
|
||||||
|
|
||||||
|
TsLineSeries = class(TsCustomLineSeries)
|
||||||
|
public
|
||||||
|
property Symbol;
|
||||||
|
property SymbolBorder;
|
||||||
|
property SymbolFill;
|
||||||
|
property SymbolHeight;
|
||||||
|
property SymbolWidth;
|
||||||
|
property ShowLines;
|
||||||
|
property ShowSymbols;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
TsPieSeries = class(TsChartSeries)
|
TsPieSeries = class(TsChartSeries)
|
||||||
@ -487,7 +487,7 @@ type
|
|||||||
destructor Destroy; override;
|
destructor Destroy; override;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
TsScatterSeries = class(TsLineSeries)
|
TsCustomScatterSeries = class(TsCustomLineSeries)
|
||||||
private
|
private
|
||||||
FRegression: TsChartRegression;
|
FRegression: TsChartRegression;
|
||||||
public
|
public
|
||||||
@ -496,6 +496,28 @@ type
|
|||||||
property Regression: TsChartRegression read FRegression write FRegression;
|
property Regression: TsChartRegression read FRegression write FRegression;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
TsScatterSeries = class(TsCustomScatterSeries)
|
||||||
|
public
|
||||||
|
property Symbol;
|
||||||
|
property SymbolBorder;
|
||||||
|
property SymbolFill;
|
||||||
|
property SymbolHeight;
|
||||||
|
property SymbolWidth;
|
||||||
|
property ShowLines;
|
||||||
|
property ShowSymbols;
|
||||||
|
end;
|
||||||
|
|
||||||
|
TsBubbleSeries = class(TsCustomScatterSeries)
|
||||||
|
private
|
||||||
|
FBubbleRange: TsChartRange;
|
||||||
|
public
|
||||||
|
constructor Create(AChart: TsChart); override;
|
||||||
|
destructor Destroy; override;
|
||||||
|
procedure SetBubbleRange(ARow1, ACol1, ARow2, ACol2: Cardinal);
|
||||||
|
procedure SetBubbleRange(ASheet1: String; ARow1, ACol1: Cardinal; ASheet2: String; ARow2, ACol2: Cardinal);
|
||||||
|
property BubbleRange: TsChartRange read FBubbleRange;
|
||||||
|
end;
|
||||||
|
|
||||||
TsChartSeriesList = class(TFPObjectList)
|
TsChartSeriesList = class(TFPObjectList)
|
||||||
private
|
private
|
||||||
function GetItem(AIndex: Integer): TsChartSeries;
|
function GetItem(AIndex: Integer): TsChartSeries;
|
||||||
@ -1428,9 +1450,9 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
{ TsLineSeries }
|
{ TsCustomLineSeries }
|
||||||
|
|
||||||
constructor TsLineSeries.Create(AChart: TsChart);
|
constructor TsCustomLineSeries.Create(AChart: TsChart);
|
||||||
begin
|
begin
|
||||||
inherited Create(AChart);
|
inherited Create(AChart);
|
||||||
FChartType := ctLine;
|
FChartType := ctLine;
|
||||||
@ -1445,18 +1467,18 @@ begin
|
|||||||
FBorder.Color := scBlack;
|
FBorder.Color := scBlack;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
destructor TsLineSeries.Destroy;
|
destructor TsCustomLineSeries.Destroy;
|
||||||
begin
|
begin
|
||||||
FBorder.Free;
|
FBorder.Free;
|
||||||
inherited;
|
inherited;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TsLineSeries.GetSymbolFill: TsChartFill;
|
function TsCustomLineSeries.GetSymbolFill: TsChartFill;
|
||||||
begin
|
begin
|
||||||
Result := FFill;
|
Result := FFill;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TsLineSeries.SetSymbolFill(Value: TsChartFill);
|
procedure TsCustomLineSeries.SetSymbolFill(Value: TsChartFill);
|
||||||
begin
|
begin
|
||||||
FFill := Value;
|
FFill := Value;
|
||||||
end;
|
end;
|
||||||
@ -1574,16 +1596,16 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
{ TsScatterSeries }
|
{ TsCustomScatterSeries }
|
||||||
|
|
||||||
constructor TsScatterSeries.Create(AChart: TsChart);
|
constructor TsCustomScatterSeries.Create(AChart: TsChart);
|
||||||
begin
|
begin
|
||||||
inherited Create(AChart);
|
inherited Create(AChart);
|
||||||
FChartType := ctScatter;
|
FChartType := ctScatter;
|
||||||
FRegression := TsChartRegression.Create;
|
FRegression := TsChartRegression.Create;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
destructor TsScatterSeries.Destroy;
|
destructor TsCustomScatterSeries.Destroy;
|
||||||
begin
|
begin
|
||||||
FRegression.Free;
|
FRegression.Free;
|
||||||
inherited;
|
inherited;
|
||||||
|
@ -3202,8 +3202,8 @@ begin
|
|||||||
|
|
||||||
series := AChart.Series[ASeriesIndex];
|
series := AChart.Series[ASeriesIndex];
|
||||||
|
|
||||||
// These are the x values of a scatter or bubble plot.
|
// These are the x values of a scatter plot.
|
||||||
if (series is TsScatterSeries) or (series is TsBubbleSeries) then
|
if (series is TsScatterSeries) then
|
||||||
begin
|
begin
|
||||||
domainRangeX := GetSheetCellRangeString_ODS(
|
domainRangeX := GetSheetCellRangeString_ODS(
|
||||||
series.XRange.GetSheet1Name, series.XRange.GetSheet2Name,
|
series.XRange.GetSheet1Name, series.XRange.GetSheet2Name,
|
||||||
|
@ -63,6 +63,7 @@ type
|
|||||||
protected
|
protected
|
||||||
FCurItem: TChartDataItem;
|
FCurItem: TChartDataItem;
|
||||||
function BuildRangeStr(AIndex: TsXYLRange; AListSeparator: char = #0): String;
|
function BuildRangeStr(AIndex: TsXYLRange; AListSeparator: char = #0): String;
|
||||||
|
procedure ClearRanges;
|
||||||
function CountValues(AIndex: TsXYLRange): Integer;
|
function CountValues(AIndex: TsXYLRange): Integer;
|
||||||
function GetCount: Integer; override;
|
function GetCount: Integer; override;
|
||||||
function GetItem(AIndex: Integer): PChartDataItem; override;
|
function GetItem(AIndex: Integer): PChartDataItem; override;
|
||||||
@ -141,7 +142,7 @@ type
|
|||||||
procedure UpdateAreaSeries(AWorkbookSeries: TsAreaSeries; AChartSeries: TAreaSeries);
|
procedure UpdateAreaSeries(AWorkbookSeries: TsAreaSeries; AChartSeries: TAreaSeries);
|
||||||
procedure UpdateBarSeries(AWorkbookSeries: TsBarSeries; AChartSeries: TBarSeries);
|
procedure UpdateBarSeries(AWorkbookSeries: TsBarSeries; AChartSeries: TBarSeries);
|
||||||
procedure UpdateBubbleSeries(AWorkbookSeries: TsBubbleSeries; AChartSeries: TBubbleSeries);
|
procedure UpdateBubbleSeries(AWorkbookSeries: TsBubbleSeries; AChartSeries: TBubbleSeries);
|
||||||
procedure UpdateLineSeries(AWorkbookSeries: TsLineSeries; AChartSeries: TLineSeries);
|
procedure UpdateCustomLineSeries(AWorkbookSeries: TsCustomLineSeries; AChartSeries: TLineSeries);
|
||||||
procedure UpdatePieSeries(AWorkbookSeries: TsPieSeries; AChartSeries: TPieSeries);
|
procedure UpdatePieSeries(AWorkbookSeries: TsPieSeries; AChartSeries: TPieSeries);
|
||||||
procedure UpdatePolarSeries(AWorkbookSeries: TsRadarSeries; AChartSeries: TPolarSeries);
|
procedure UpdatePolarSeries(AWorkbookSeries: TsRadarSeries; AChartSeries: TPolarSeries);
|
||||||
procedure UpdateScatterSeries(AWorkbookSeries: TsScatterSeries; AChartSeries: TLineSeries);
|
procedure UpdateScatterSeries(AWorkbookSeries: TsScatterSeries; AChartSeries: TLineSeries);
|
||||||
@ -173,6 +174,7 @@ uses
|
|||||||
|
|
||||||
type
|
type
|
||||||
TBasicPointSeriesOpener = class(TBasicPointSeries);
|
TBasicPointSeriesOpener = class(TBasicPointSeries);
|
||||||
|
TsCustomLineSeriesOpener = class(TsCustomLineSeries);
|
||||||
|
|
||||||
function mmToPx(mm: Double; ppi: Integer): Integer;
|
function mmToPx(mm: Double; ppi: Integer): Integer;
|
||||||
begin
|
begin
|
||||||
@ -304,15 +306,7 @@ end;
|
|||||||
constructor TsWorkbookChartSource.Create(AOwner: TComponent);
|
constructor TsWorkbookChartSource.Create(AOwner: TComponent);
|
||||||
begin
|
begin
|
||||||
inherited;
|
inherited;
|
||||||
SetLength(FRanges[rngX], 1);
|
ClearRanges;
|
||||||
SetLength(FRanges[rngY], 1);
|
|
||||||
SetLength(FRanges[rngLabel], 1);
|
|
||||||
SetLength(FRanges[rngColor], 1);
|
|
||||||
|
|
||||||
SetLength(FWorksheets[rngX], 1);
|
|
||||||
SetLength(FWorksheets[rngY], 1);
|
|
||||||
SetLength(FWorksheets[rngLabel], 1);
|
|
||||||
Setlength(FWorksheets[rngColor], 1);
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{@@ ----------------------------------------------------------------------------
|
{@@ ----------------------------------------------------------------------------
|
||||||
@ -380,6 +374,25 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TsWorkbookChartSource.ClearRanges;
|
||||||
|
begin
|
||||||
|
SetLength(FRanges[rngX], 1); FRanges[rngX, 0 ] := nil;
|
||||||
|
SetLength(FRanges[rngY], 1); FRanges[rngY, 0] := nil;
|
||||||
|
SetLength(FRanges[rngLabel], 1); FRanges[rngLabel, 0] := nil;
|
||||||
|
SetLength(FRanges[rngColor], 1); FRanges[rngColor, 0] := nil;
|
||||||
|
|
||||||
|
SetLength(FWorksheets[rngX], 1); FWorksheets[rngX, 0] := nil;
|
||||||
|
SetLength(FWorksheets[rngY], 1); FWorksheets[rngY, 0] := nil;
|
||||||
|
SetLength(FWorksheets[rngLabel], 1); FWorksheets[rngLabel, 0] := nil;
|
||||||
|
SetLength(FWorksheets[rngColor], 1); FWorksheets[rngColor, 0] := nil;
|
||||||
|
|
||||||
|
FRangeStr[rngX] := '';
|
||||||
|
FRangeStr[rngY] := '';
|
||||||
|
FRangeStr[rngLabel] := '';
|
||||||
|
FRangeStr[rngColor] := '';
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
{@@ ----------------------------------------------------------------------------
|
{@@ ----------------------------------------------------------------------------
|
||||||
Counts the number of x or y values contained in the x/y ranges
|
Counts the number of x or y values contained in the x/y ranges
|
||||||
|
|
||||||
@ -620,7 +633,10 @@ begin
|
|||||||
|
|
||||||
// Workbook has been successfully loaded, all sheets are ready
|
// Workbook has been successfully loaded, all sheets are ready
|
||||||
if (lniWorkbook in AChangedItems) then
|
if (lniWorkbook in AChangedItems) then
|
||||||
|
begin
|
||||||
|
ClearRanges;
|
||||||
Prepare;
|
Prepare;
|
||||||
|
end;
|
||||||
|
|
||||||
// Used worksheet has been renamed?
|
// Used worksheet has been renamed?
|
||||||
if (lniWorksheetRename in AChangedItems) then
|
if (lniWorksheetRename in AChangedItems) then
|
||||||
@ -896,7 +912,6 @@ begin
|
|||||||
FWorkbookSource := AValue;
|
FWorkbookSource := AValue;
|
||||||
if FWorkbookSource <> nil then
|
if FWorkbookSource <> nil then
|
||||||
FWorkbookSource.AddListener(self);
|
FWorkbookSource.AddListener(self);
|
||||||
// FWorkbook := GetWorkbook;
|
|
||||||
ListenerNotification([lniWorkbook, lniWorksheet]);
|
ListenerNotification([lniWorkbook, lniWorksheet]);
|
||||||
Prepare;
|
Prepare;
|
||||||
end;
|
end;
|
||||||
@ -1017,6 +1032,8 @@ begin
|
|||||||
Result := TBubbleSeries.Create(FChart);
|
Result := TBubbleSeries.Create(FChart);
|
||||||
src.SetYRange(1, TsBubbleSeries(ASeries).BubbleRange);
|
src.SetYRange(1, TsBubbleSeries(ASeries).BubbleRange);
|
||||||
end;
|
end;
|
||||||
|
ctPie:
|
||||||
|
Result := TPieSeries.Create(FChart);
|
||||||
else
|
else
|
||||||
exit(nil);
|
exit(nil);
|
||||||
end;
|
end;
|
||||||
@ -1079,7 +1096,7 @@ begin
|
|||||||
ctBubble:
|
ctBubble:
|
||||||
UpdateBubbleSeries(TsBubbleSeries(ASeries), TBubbleSeries(ser));
|
UpdateBubbleSeries(TsBubbleSeries(ASeries), TBubbleSeries(ser));
|
||||||
ctLine:
|
ctLine:
|
||||||
UpdateLineSeries(TsLineSeries(ASeries), TLineSeries(ser));
|
UpdateCustomLineSeries(TsLineSeries(ASeries), TLineSeries(ser));
|
||||||
ctScatter:
|
ctScatter:
|
||||||
UpdateScatterSeries(TsScatterSeries(ASeries), TLineSeries(ser));
|
UpdateScatterSeries(TsScatterSeries(ASeries), TLineSeries(ser));
|
||||||
ctPie, ctRing:
|
ctPie, ctRing:
|
||||||
@ -1347,7 +1364,11 @@ end;
|
|||||||
procedure TsWorkbookChartLink.ListenerNotification(AChangedItems: TsNotificationItems;
|
procedure TsWorkbookChartLink.ListenerNotification(AChangedItems: TsNotificationItems;
|
||||||
AData: Pointer = nil);
|
AData: Pointer = nil);
|
||||||
begin
|
begin
|
||||||
// to be completed
|
Unused(AData);
|
||||||
|
|
||||||
|
// Workbook has been successfully loaded, all sheets are ready
|
||||||
|
if (lniWorkbook in AChangedItems) then
|
||||||
|
ClearChart;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TsWorkbookChartLink.Notification(AComponent: TComponent; Operation: TOperation);
|
procedure TsWorkbookChartLink.Notification(AComponent: TComponent; Operation: TOperation);
|
||||||
@ -1561,49 +1582,6 @@ begin
|
|||||||
FChart.Frame.Visible := AWorkbookChart.PlotArea.Border.Style <> clsNoLine;
|
FChart.Frame.Visible := AWorkbookChart.PlotArea.Border.Style <> clsNoLine;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{
|
|
||||||
procedure TsWorkbookChartLink.UpdateBarSeries(AWorkbookChart: TsChart);
|
|
||||||
var
|
|
||||||
i, n: Integer;
|
|
||||||
ser: TBarSeries;
|
|
||||||
barWidth, totalBarWidth: Integer;
|
|
||||||
begin
|
|
||||||
if AWorkbookChart.GetChartType <> ctBar then
|
|
||||||
exit;
|
|
||||||
|
|
||||||
// Count the bar series
|
|
||||||
n := 0;
|
|
||||||
for i := 0 to AWorkbookChart.Series.Count-1 do
|
|
||||||
begin
|
|
||||||
if AWorkbookChart.Series[i].ChartType = ctBar then
|
|
||||||
inc(n);
|
|
||||||
end;
|
|
||||||
|
|
||||||
// Iterate over bar series to put them side-by-side or to stack them
|
|
||||||
totalBarWidth := 90;
|
|
||||||
barWidth := round(totalBarWidth / n);
|
|
||||||
for i := 0 to FChart.SeriesCount-1 do
|
|
||||||
if FChart.Series[i] is TBarSeries then
|
|
||||||
begin
|
|
||||||
ser := TBarSeries(FChart.Series[i]);
|
|
||||||
case AWorkbookChart.Stackmode of
|
|
||||||
csmSideBySide:
|
|
||||||
begin
|
|
||||||
ser.BarWidthPercent := barWidth;
|
|
||||||
ser.BarWidthStyle := bwPercentMin;
|
|
||||||
ser.BarOffsetPercent := round((i - (n - 1)/2)*barWidth);
|
|
||||||
end;
|
|
||||||
csmStacked:
|
|
||||||
ser.Stacked := true;
|
|
||||||
csmStackedPercentage:
|
|
||||||
begin
|
|
||||||
ser.Stacked := true;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
}
|
|
||||||
|
|
||||||
procedure TsWorkbookChartLink.UpdateChartBrush(AWorkbookChart: TsChart;
|
procedure TsWorkbookChartLink.UpdateChartBrush(AWorkbookChart: TsChart;
|
||||||
AWorkbookFill: TsChartFill; ABrush: TBrush);
|
AWorkbookFill: TsChartFill; ABrush: TBrush);
|
||||||
var
|
var
|
||||||
@ -1763,7 +1741,7 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TsWorkbookChartLink.UpdateLineSeries(AWorkbookSeries: TsLineSeries;
|
procedure TsWorkbookChartLink.UpdateCustomLineSeries(AWorkbookSeries: TsCustomLineSeries;
|
||||||
AChartSeries: TLineSeries);
|
AChartSeries: TLineSeries);
|
||||||
const
|
const
|
||||||
POINTER_STYLES: array[TsChartSeriesSymbol] of TSeriesPointerstyle = (
|
POINTER_STYLES: array[TsChartSeriesSymbol] of TSeriesPointerstyle = (
|
||||||
@ -1781,19 +1759,20 @@ const
|
|||||||
);
|
);
|
||||||
var
|
var
|
||||||
ppi: Integer;
|
ppi: Integer;
|
||||||
|
openedWorkbookSeries: TsCustomLineSeriesOpener absolute AWorkbookSeries;
|
||||||
begin
|
begin
|
||||||
ppi := GetParentForm(FChart).PixelsPerInch;
|
ppi := GetParentForm(FChart).PixelsPerInch;
|
||||||
|
|
||||||
UpdateChartPen(AWorkbookSeries.Chart, AWorkbookSeries.Line, AChartSeries.LinePen);
|
UpdateChartPen(AWorkbookSeries.Chart, AWorkbookSeries.Line, AChartSeries.LinePen);
|
||||||
AChartSeries.ShowLines := AWorkbookSeries.Line.Style <> clsNoLine;
|
AChartSeries.ShowLines := AWorkbookSeries.Line.Style <> clsNoLine;
|
||||||
AChartSeries.ShowPoints := AWorkbookSeries.ShowSymbols;
|
AChartSeries.ShowPoints := openedWorkbookSeries.ShowSymbols;
|
||||||
if AChartSeries.ShowPoints then
|
if AChartSeries.ShowPoints then
|
||||||
begin
|
begin
|
||||||
UpdateChartBrush(AWorkbookSeries.Chart, AWorkbookSeries.Fill, AChartSeries.Pointer.Brush);
|
UpdateChartBrush(AWorkbookSeries.Chart, AWorkbookSeries.Fill, AChartSeries.Pointer.Brush);
|
||||||
AChartSeries.Pointer.Pen.Color := AChartSeries.LinePen.Color;
|
AChartSeries.Pointer.Pen.Color := AChartSeries.LinePen.Color;
|
||||||
AChartSeries.Pointer.Style := POINTER_STYLES[AWorkbookSeries.Symbol];
|
AChartSeries.Pointer.Style := POINTER_STYLES[openedWorkbookSeries.Symbol];
|
||||||
AChartSeries.Pointer.HorizSize := mmToPx(AWorkbookSeries.SymbolWidth, ppi);
|
AChartSeries.Pointer.HorizSize := mmToPx(openedWorkbookSeries.SymbolWidth, ppi);
|
||||||
AChartSeries.Pointer.VertSize := mmToPx(AWorkbookSeries.SymbolHeight, ppi);
|
AChartSeries.Pointer.VertSize := mmToPx(openedWorkbookSeries.SymbolHeight, ppi);
|
||||||
end;
|
end;
|
||||||
AChartSeries.Stacked := AWorkbookSeries.Chart.StackMode <> csmSideBySide;
|
AChartSeries.Stacked := AWorkbookSeries.Chart.StackMode <> csmSideBySide;
|
||||||
if AChartSeries.Source is TCalculatedChartSource then
|
if AChartSeries.Source is TCalculatedChartSource then
|
||||||
@ -1838,7 +1817,7 @@ var
|
|||||||
ser: TFitSeries;
|
ser: TFitSeries;
|
||||||
s: String;
|
s: String;
|
||||||
begin
|
begin
|
||||||
UpdateLineSeries(AWorkbookSeries, AChartSeries);
|
UpdateCustomLineSeries(AWorkbookSeries, AChartSeries);
|
||||||
|
|
||||||
if AWorkbookSeries.Regression.RegressionType = rtNone then
|
if AWorkbookSeries.Regression.RegressionType = rtNone then
|
||||||
exit;
|
exit;
|
||||||
|
@ -1331,12 +1331,21 @@ var
|
|||||||
begin
|
begin
|
||||||
for j:=0 to FListeners.Count-1 do begin
|
for j:=0 to FListeners.Count-1 do begin
|
||||||
C := TComponent(FListeners[j]);
|
C := TComponent(FListeners[j]);
|
||||||
if C.GetInterface(GUID_SpreadsheetControl, I) then
|
if (C <> nil) then
|
||||||
I.ListenerNotification(AChangedItems, AData)
|
begin
|
||||||
else
|
if C.GetInterface(GUID_SpreadsheetControl, I) then
|
||||||
raise Exception.CreateFmt('[TsWorkbookSource.NotifyListeners] Class %s is not prepared to be a spreadsheet listener.',
|
I.ListenerNotification(AChangedItems, AData)
|
||||||
[C.ClassName]);
|
else
|
||||||
|
raise Exception.CreateFmt('[TsWorkbookSource.NotifyListeners] Class %s is not prepared to be a spreadsheet listener.',
|
||||||
|
[C.ClassName]);
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
// Cleanup listener list from removed listeners (= set to nil) while
|
||||||
|
// NotifyListeners was running
|
||||||
|
for j := FListeners.Count-1 downto 0 do
|
||||||
|
if FListeners[j] = nil then
|
||||||
|
FListeners.Delete(j);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{@@ ----------------------------------------------------------------------------
|
{@@ ----------------------------------------------------------------------------
|
||||||
@ -1355,11 +1364,20 @@ begin
|
|||||||
C := TComponent(FListeners[j]);
|
C := TComponent(FListeners[j]);
|
||||||
if C = AListener then
|
if C = AListener then
|
||||||
begin
|
begin
|
||||||
FListeners.Delete(j);
|
FListeners[j] := nil;
|
||||||
if C.GetInterface(GUID_SpreadsheetControl, I) then
|
// Do not delete the listener here (FListeners.Delete(j)) because
|
||||||
I.RemoveWorkbookSource
|
// RemoveListeners may be called while NotifyListeners is still running.
|
||||||
else
|
// The problem can be that a chart may destroy a listening chart source
|
||||||
raise Exception.CreateFmt('Class %s not prepared for listening.',[AListener.ClassName]);
|
// which would trigger RemoveListener. If the chart source then would be
|
||||||
|
// deleted from the list the NotifiyListeners loop would access
|
||||||
|
// unallocated memory --> crash
|
||||||
|
if C <> nil then
|
||||||
|
begin
|
||||||
|
if C.GetInterface(GUID_SpreadsheetControl, I) then
|
||||||
|
I.RemoveWorkbookSource
|
||||||
|
else
|
||||||
|
raise Exception.CreateFmt('Class %s not prepared for listening.',[AListener.ClassName]);
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
Reference in New Issue
Block a user