3

我无法在 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 但经过多次试验和阅读有关组件流的文档后,我看不出如何构建它。有人可以评论吗?非常感谢。

4

0 回答 0