我无法在 Delphi 中重新加载保存的复合组件,其中子组件(TChart)似乎被创建了两次。当我在代码中创建我的组件时,它工作正常。
我的组件是一个托管与客户端对齐的 TChart 的 TPanel,我自己创建了单个系列及其数据。这是我的代码:
type
TMyChart = class( TPanel )
PRIVATE
FChart : TChart;
PROTECTED
procedure Notification( AComponent : TComponent; Operation : TOperation ); override;
PUBLIC
constructor Create( AOwner : TComponent ); override;
destructor Destroy; override;
PUBLISHED
property Chart : TChart
read FChart;
end;
{ TMyChart }
constructor TMyChart.Create(AOwner: TComponent);
begin
inherited;
Width := 400;
Height := 150;
FChart := TChart.Create( Self );
FChart.Name := '';
FChart.SetSubComponent( True );
FChart.FreeNotification( Self );
FChart.Parent := Self;
FChart.Align := alClient;
FChart.AddSeries( TLineSeries.Create( FChart ));
FChart.Series[0].FillSampleValues(100);
end;
destructor TMyChart.Destroy;
begin
FreeAndNil( FChart );
inherited;
end;
procedure TMyChart.Notification(AComponent: TComponent; Operation: TOperation);
begin
inherited;
if (AComponent = FChart) and (Operation = opRemove) then
FChart := nil;
end;
initialization
RegisterClass( TMyChart );
RegisterClass( TChart );
RegisterClass( TLineSeries );
end.
我已经按照 ExtCtrls 'TLabeledEdit' 中的示例为子组件 TChart 包含了一个 FreeNotification。
我使用 TStream.WriteComponent 将其流式传输并获得以下 DFM:
object Mychart1: TMyChart
Left = 0
Top = 0
Width = 400
Height = 150
Caption = 'Mychart1'
TabOrder = 3
Chart.Left = 1
Chart.Top = 1
Chart.Width = 398
Chart.Height = 148
Chart.Align = alClient
Chart.TabOrder = 0
Chart.ColorPaletteIndex = 13
object TChart
Left = 1
Top = 1
Width = 398
Height = 148
Align = alClient
TabOrder = 0
ColorPaletteIndex = 13
object TLineSeries
Marks.Arrow.Visible = True
Marks.Callout.Brush.Color = clBlack
Marks.Callout.Arrow.Visible = True
Marks.ShapeStyle = fosRoundRectangle
Marks.Visible = False
Brush.BackColor = clDefault
Pointer.InflateMargins = True
Pointer.Style = psRectangle
Pointer.Visible = False
XValues.Name = 'X'
XValues.Order = loAscending
YValues.Name = 'Y'
YValues.Order = loNone
end
end
end
我需要的一切都在那里。我使用 ReadComponent 重新加载此 DFM,如下所示:
procedure LoadComponentFromFile( var AComponent : TComponent );
var
MS : TMemoryStream;
SS : TStringStream;
begin
MS := TMemoryStream.Create;
SS := TStringStream.Create;
try
SS.LoadFromFile( GetSpecialFolderPath( CSIDL_DESKTOP ) + '\test.txt' );
SS.Position := 0;
ObjectTextToBinary( SS, MS );
MS.Position := 0;
AComponent := MS.ReadComponent( nil );
finally
MS.Free;
SS.Free;
end;
end;
procedure TForm8.Button3Click(Sender: TObject);
begin
FreeAndNil( FMyChart );
LoadComponentFromFile( TComponent(FMyChart) );
FMyChart.Parent := Self;
end;
在此之后,我似乎创建了两个 TChart - 一个具有正确的系列数据(由 TMyChart.Create 构建),另一个(在此前面)具有空轴,大概是 ReadComponent 正在构造“对象 TChart”的地方。我已经通过在“TMyChart.Create”中放置一个断点和在“TCustomChart.Create”中的 TChart 源代码中放置另一个断点来证明这一点。调用加载程序代码时,它会先命中 TMyChart.Create 断点一次,然后再命中 TCustomChart.Create 断点两次。我可以看到我需要告诉 TStream.ReadComponent 不要重新创建我的子组件 TChart 但经过多次试验和阅读有关组件流的文档后,我看不出如何构建它。有人可以评论吗?非常感谢。