Delphi stream panel to file

这一生的挚爱 提交于 2020-03-02 07:35:46

问题


today I've a question about streaming a part of a form to a file. In this example i use a Tmemo instead of file in order to see the stream.

here is my form:

The panel on the right top of the form has some controls, like label, edit and so on. with the "Save panel" butto I save the panel on a TStream:

Here the code:

procedure TfrmMain.btnSaveClick(Sender: TObject);
var
  idx: Integer;
  MemStr: TStream;
begin
  MemStr := TMemoryStream.Create;
  PanelStr := TMemoryStream.Create;
  try
    for idx := 0 to pnlSource.ControlCount - 1 do begin
      MemStr.Position := 0;
      MemStr.WriteComponent(pnlSource.Controls[idx]);
      StreamConvert(MemStr);
    end;
    PanelStr.Position := 0;
    mmoStream.Lines.LoadFromStream(PanelStr);
  finally
    MemStr.Free;
  end;
end;

and here the StreamConvert:

{ Conversione stream in formato testo }
procedure TfrmMain.StreamConvert(aStream: TStream);
var
  ConvStream: TStream;
begin
  aStream.Position := 0;
  ConvStream := TMemoryStream.Create;
  try
    ObjectBinaryToText(aStream, ConvStream);
    ConvStream.Position := 0;
    PanelStr.CopyFrom(ConvStream, ConvStream.Size);
    lblStreamSize.Caption := IntToStr(ConvStream.Size);
  finally
    ConvStream.Free;
  end;
end;

PanelStr is a TStream object declared in private section of the form and create during form create. This part works good and, as you can see in right part of the image the elements present on the form are register correctly.

Now my problem is to restore this element into the panel on the left bottom of the form. I've tryed this routine:

{ Carica i controlli presenti nel pannello pnlSource in uno stream }
procedure TfrmMain.btnLoadClick(Sender: TObject);
var
  idx:  Integer;
  MemStr: TStream;
begin
  pnlSource.Free;
  MemStr := TMemoryStream.Create;
  try
    PanelStr.Position := 0;
    ObjectTextToBinary(PanelStr, MemStr);
    MemStr.Position := 0;
    MemStr.ReadComponent(pnlTarget);
  finally
    MemStr.Free;
  end;
end;

but it doesn't work and in the following picture you can see the result:

What is wrong in my routine, and How can I read all the element present in the stream and not only the first?

Can someone help me in this headache?


回答1:


The code you are currently running effectively transforms the source panel to a label. That's because the first object streamed is a label and the code is reading only one component. IOW, when the reader reaches the first end, reading is complete since there are no sub controls in the stream.

So, first of all, you have to write the panel - and only the panel. The panel is the one that is supposed to stream it's children. To have it to do so, it must own it's controls.

var
  idx: Integer;
  MemStr: TStream;
begin
  MemStr := TMemoryStream.Create;
  PanelStr := TMemoryStream.Create;
  try
    // transfer ownership of controls to the panel
    for idx := 0 to pnlSource.ControlCount - 1 do
      pnlSource.InsertComponent(pnlSource.Controls[idx]);
    // write the panel
    MemStr.WriteComponent(pnlSource);

    StreamConvert(MemStr);
    PanelStr.Position := 0;
    mmoStream.Lines.LoadFromStream(PanelStr);
  finally
    MemStr.Free;
  end;

This produces an output to the memo like this:

object pnlSource: TPanel
  Left = 8
  Top = 8
  Width = 201
  Height = 265
  Caption = 'pnlSource'
  TabOrder = 0
  object Label1: TLabel
    Left = 48
    Top = 208
    Width = 31
    Height = 13
    Caption = 'Label1'
  end
  object Label2: TLabel
    ...

Note the indentation of the label definition and the missing 'end' of the owning panel (it's at the end).

You will need to register classes for the streamer to be able to find them when loading:

var
  idx:  Integer;
  MemStr: TStream;
begin
  pnlSource.Free;

  RegisterClasses([TLabel, TEdit, TCheckBox, TRadioButton]);

  MemStr := TMemoryStream.Create;
  try
    PanelStr.Position := 0;
    ObjectTextToBinary(PanelStr, MemStr);
    MemStr.Position := 0;
    MemStr.ReadComponent(pnlTarget);
  finally
    MemStr.Free;
  end;

Registration can be of course moved to elsewhere, like form creation or unit initialization.

You can also transfer ownership of the controls back to the form if it's required, like in the saving code.




回答2:


As I put in my comments, you need to surround your data with Panel2 information. You also need to register each control type you are saving and restoring.

This means that only the load procedure needs to change - like this:

procedure TfrmMain.btnLoadClick(Sender: TObject);
var
  iTemp, iTemp2 : TStringList;
  MemStr: TStream;
  i: Integer;
begin
  // first read the destination panel an put it into a string list
  pnlSource.Free;
  iTemp := TStringList.Create;
  iTemp2 := TStringList.Create;
  iTemp.Duplicates := TDuplicates.dupAccept;
  iTemp2.Duplicates := TDuplicates.dupAccept;
  MemStr := TMemoryStream.Create;
  try
    PanelStr.Position := 0;
    iTemp2.LoadFromStream( PanelStr ); // our original source
    PanelStr.Size := 0;
    MemStr.Position := 0;
    MemStr.WriteComponent(pnlTarget);
    StreamConvert(MemStr);
    // PanelStr now has our destination poanel.
    PanelStr.Position := 0;
    iTemp.LoadFromStream( PanelStr );
    for i := 0 to iTemp2.Count - 1 do
    begin
      iTemp.Insert( ITemp.Count - 1, iTemp2[ i ]);
    end;
    PanelStr.Size := 0;
    iTemp.SaveToStream( PanelStr );
    PanelStr.Position := 0;
    mmoStream.Lines.LoadFromStream(PanelStr);
    MemStr.Size := 0;
    PanelStr.Position := 0;
    ObjectTextToBinary( PanelStr, MemStr);
    MemStr.Position := 0;
    RegisterClass( TLabel );
    RegisterClass( TPanel );
    RegisterClass( TEdit );
    RegisterClass( TCheckBox );
    RegisterClass( TRadioButton );
    MemStr.ReadComponent( pnlTarget );

  finally
    iTemp.Free;
    iTemp2.Free;
    MemStr.Free;
  end;
end;

As commented in the previous answer, registration can be put somewhere else.

Unlike the previous answer, you do not need to change the ownership of the controls first. (That is just a comment - not a criticism). This is just an implementation of my comment.

My naming conventions are different to yours. I have tried to use the same names, but forgive me if I have missed any.



来源:https://stackoverflow.com/questions/41021756/delphi-stream-panel-to-file

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!