我想用 TMemoryStream 保存并且读取窗体的所有内容。因为一旦控件多了,用INI文件会很麻烦。
可是就是这么简单的程序还时出错,当写入文件时没有任何问题。
可是读取以前保存的文件会出现下面的问题:
1、当用 ReadComponent 读取内容到控件后,窗体的名字会在原来的基础上加 _1 ,比如原来的窗体名称 Form1 ,那么读取后变成了 Form1_1 。如果再次调用 WriteComponent ,那么依此类推,后面会添加无数个 _1 。
   这个问题不通过改变窗体名能解决吗?能分析一下怎么回事吗?2、多次调用 ReadComponent 读取内容到控件后会出现错误。其他想要实现的功能:
1、在用 TMemoryStream 保存窗体内容时,是否能修改 TMemoryStream 中已经保存的窗体属性然后再写入到文件。
如果大家还有什么其他保存窗体完整内容方法,请不吝赐教。谢谢!这是我试验的代码。unit Unit1;interfaceuses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;var
  Form1: TForm1;implementationuses
  Unit2;
{$R *.dfm}procedure TForm1.Button1Click(Sender: TObject);
var
  ms: TMemoryStream;
begin
  ms:=TMemoryStream.Create;
  try
    ms.WriteComponent(Self);
    ms.SaveToFile('d:\a.txt');
  finally
    ms.Free;
  end;
end;procedure TForm1.Button2Click(Sender: TObject);
var
  ms: TMemoryStream;
  i: Integer;
begin
  ms:=TMemoryStream.Create;
  try
    ms.LoadFromFile('d:\a.txt');
    
    for i := Self.ComponentCount - 1 downto 0 do
      Self.Components[i].Free;    ShowMessage(Self.Name);    ms.ReadComponent(Self);    ShowMessage(Self.Name);
  finally
    ms.Free;
  end;
end;
end.

解决方案 »

  1.   

    for i := Self.ComponentCount - 1 downto 0 do
          Self.Components[i].Free;
        self.Name := '';//把name置空,就不会变成_1了
      

  2.   

    读取控件时需要用RegisterClass注册一下类的。参考一下Inside VCL里的一个例子:  (\源代码\Chap08\DynamicCheckBox.pas)unit fmDynamicCheckBox;interfaceuses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, Buttons, StdCtrls;type
      TForm1 = class(TForm)
        GroupBox1: TGroupBox;
        btnCreateCheckBox: TButton;
        btnLoadCheckBox: TButton;
        btnSaveCheckBox: TButton;
        BitBtn1: TBitBtn;
        procedure btnCreateCheckBoxClick(Sender: TObject);
        procedure FormCreate(Sender: TObject);
        procedure FormDestroy(Sender: TObject);
        procedure btnSaveCheckBoxClick(Sender: TObject);
        procedure btnLoadCheckBoxClick(Sender: TObject);
      private
        { Private declarations }
        aList : TList;    procedure DeleteCheckBoxes;
        procedure RegisterCheckBoxClass;
        procedure LoadCheckBoxes;
      public
        { Public declarations }
      end;var
      Form1: TForm1;implementation{$R *.dfm}const
      OFFSET = 40;
      CMPFILENAME = 'custommizedComponents.cks';procedure TForm1.btnCreateCheckBoxClick(Sender: TObject);
    var
      iCount , iYPos : Integer;
      aCB : TCheckBox;
    begin
      iYPos := 30;  for iCount := 1 to 5 do
      begin
        aCB := TCheckBox.Create(Self);
        aCB.Parent := Self.GroupBox1;
        aCB.Left := 10;
        aCB.Top := iYPos;
        aCB.Width := 300;
        aCB.Caption := 'CheckBox控件' + IntToStr(iCount);
        Inc(iYPos, OFFSET);
        aList.Add(aCB);
      end;
    end;procedure TForm1.FormCreate(Sender: TObject);
    begin
      aList := TList.Create;
    end;procedure TForm1.FormDestroy(Sender: TObject);
    begin
      FreeAndNil(aList);
    end;procedure TForm1.btnSaveCheckBoxClick(Sender: TObject);
    var
      fss : TMemoryStream;
      iCount : Integer;
    begin
      try
        fss := TMemoryStream.Create;
        for iCount := 0 to aList.Count - 1 do
          fss.WriteComponent(TCheckBox(aList.Items[iCount]));    fss.SaveToFile(CMPFILENAME);
      finally
        FreeAndNil(fss);
      end;
    end;procedure TForm1.btnLoadCheckBoxClick(Sender: TObject);
    begin
      if (FileExists(CMPFILENAME)) then
      begin
        DeleteCheckBoxes;
        RegisterCheckBoxClass;
        LoadCheckBoxes;
      end;
    end;procedure TForm1.DeleteCheckBoxes;
    var
      iCount : Integer;
    begin
      for iCount := aList.Count - 1 downto 0 do
      begin
        TCheckBox(aList.Items[iCount]).Free;
        aList.Delete(iCount);
      end;
    end;procedure TForm1.LoadCheckBoxes;
    var
      fss : TMemoryStream;
      iCount : Integer;
      acb : TCheckBox;
    begin
      try
        fss := TMemoryStream.Create;
        fss.LoadFromFile(CMPFILENAME);
        for iCount := 1 to 5 do
        begin
          acb := TCheckBox(fss.ReadComponent(nil));
          acb.Parent := Self.GroupBox1;
          acb.Font.Color := clRed;
          aList.Add(acb);
        end;
      finally
        FreeAndNil(fss);
      end;
    end;procedure TForm1.RegisterCheckBoxClass;
    begin
      try
        Classes.FindClass('TCheckBox');
      except
        on Exception do
          Classes.RegisterClass(TCheckBox);
      end;
    end;end.
      

  3.   

    你找对人了:
    http://blog.csdn.net/linzhengqun/archive/2005/10/15/504406.aspx
      

  4.   

    linzhengqun(风。我回来了)
    不好意思。我初学Delphi ,没能看出那个类怎么解决我的问题呢?
    那个类把控件变成流和MemoryStream 的 WriteComponent 方法有什么区别吗?
      

  5.   

    每次读的时候,FORM上的控件都FREE了. 而你READ出控件后,并没有CREATE.当然报错了.
    你可以改变的FORM或其它的控件的属性, 但需要CREATE后再ASSIGN.
      

  6.   

    sorry,我上面写的也算很正确.觉得LZ的做法是不正确的.因为:
    1,首先你保存的是整个Form. FREE的是Form上的Button, Form并没有FREE.所以恢复的时候会有问题.
    2,ReadComponent返回的是TComponent. 至少需要TCheckBox(fss.ReadComponent(nil));这样转换一下.并设置Parent,(最好读取控件时,要用RegisterClass注册一下类的。)
    3.Read保存的控件时,最后ReadComponent(nil);为空的话,要自动调用构造函数来创建实例.不需要再手动create方法了.
    DELPHI帮助上:
    If Instance is nil (Delphi) or NULL (C++), ReadComponent constructs a component based on the type information in the stream and returns the newly-constructed component.
      

  7.   

    jjwwang(风归叶) 你说的是正确还是不正确的?
      

  8.   

    unit Unit1;interfaceuses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, StdCtrls;type
      TForm1 = class(TForm)
        checkbox1: TCheckBox;
        procedure FormDestroy(Sender: TObject);
        procedure FormCreate(Sender: TObject);
      private
        { Private declarations }
      public
        { Public declarations }
      end;var
      Form1: TForm1;implementation{$R *.dfm}procedure TForm1.FormDestroy(Sender: TObject);
    var
      ms: TMemoryStream;
    begin
      try
        ms:= TMemoryStream.Create;
        ms.WriteComponent(checkbox1);
        ms.SaveToFile('e:\cb.ck');
      finally
        FreeAndNil(ms);
      end;
    end;procedure TForm1.FormCreate(Sender: TObject);
    var
      ms: TMemoryStream;
    begin
      try
        ms:= TMemoryStream.Create;
        if FileExists('e:\cb.ck') then
        begin
          ms.LoadFromFile('e:\cb.ck');
          checkbox1:= TCheckBox(ms.ReadComponent(checkbox1));
        end;
      finally
        FreeAndNil(ms);
      end;
    end;end.