2016-12-07 2 views
3

сегодня у меня есть вопрос о потоковой передаче части формы в файл. В этом примере я использую Tmemo вместо файла, чтобы увидеть поток.Delphi панель потока в файл

здесь моя форма:

enter image description here

панель на правой верхней части формы имеет некоторые элементы управления, как метки, редактировать и так далее. с "Сохранить панель" переключатом я сохранить панель на TStream:

Вот код:

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; 

и здесь 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 является TStream объекта объявлен в частный раздел формы и создать во время создания формы. Эта часть работает хорошо, и, как вы можете видеть в правой части изображения, элементы, находящиеся на форме, регистрируются правильно.

Теперь моя проблема заключается в том, чтобы восстановить этот элемент в панели в левом нижнем углу формы. Я судимо эту процедуру:

{ 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; 

но это не работает и на рисунке вы можете увидеть результат:

enter image description here

Что плохого в моей обычной, и как могу ли я прочитать весь элемент, присутствующий в потоке, а не только первый?

Может кто-нибудь помочь мне в этой головной боли?

+0

Насколько я вижу, список, который у вас есть, это список компонентов на исходной панели, но вы пытаетесь прочитать свойства целевой панели. Свойства отсутствуют, поскольку целевая панель не определена в вашем источнике. Что вам нужно сделать, так это прочитать свойства целевой панели и поместить их в оболочку вокруг свойств встроенных компонентов, которые вы читаете, т.е. помещать данные, показанные на правой панели, непосредственно перед конечным утверждением того, что вы читаете из если это имеет смысл. – Dsm

ответ

2

Код, который вы сейчас используете, эффективно преобразует исходную панель в ярлык. Это связано с тем, что первый объект, передаваемый потоком, является меткой, а код считывает только один компонент. IOW, когда читатель достигает первого end, чтение завершено, так как в потоке нет под элементов управления.

Итак, прежде всего, вам нужно написать панель - и только панель. Панель - это тот, который должен вытолкнуть его детей. Чтобы он это сделал, он должен иметь свои элементы управления.

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; 

Это производит вывод в памятке, как это:

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 
    ... 

Примечание отступы определения этикетки и недостающий «конец» панели владеющим (это в конце).

Вам нужно будет зарегистрировать классы для стримера, чтобы быть в состоянии найти их при загрузке:

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; 

Регистрация может быть, конечно, переехал в другом месте, как создание формы или инициализации устройства.

Вы также можете передать право собственности на элементы управления обратно в форму, если это необходимо, например, в коде сохранения.

+0

Просто, чтобы прояснить вашу первую строку. Он не изменяет TPanel на TLabel. Это все еще TPanel. Но все ReadComponent делает в исходном коде, который он читает первый объект (TLabel), игнорирует, какой тип он (документация утверждает это), и пытается применить свойства Label1 к Panel2. Так как TLabel и TPanel имеют одинаковые опубликованные свойства, поэтому исходный код не вызывает исключения, и панель перемещается в верхнюю левую сторону, как показано на рисунке, немного похожая на оригинальный Label1. – Dsm

+0

Да, хорошее описание. –

0

Как я уже писал в своих комментариях, вам необходимо объединить свои данные с информацией Panel2. Вам также необходимо зарегистрировать каждый тип управления, который вы сохраняете и восстанавливаете.

Это означает, что только процедура загрузки должна измениться - как это:

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; 

Как отметил в предыдущем ответе, регистрация может быть поставлен где-то в другом месте.

В отличие от предыдущего ответа, вам не нужно сначала менять права собственности на элементы управления. (Это всего лишь комментарий, а не критика). Это всего лишь реализация моего комментария.

Мои соглашения об именах отличаются от ваших. Я пытался использовать одни и те же имена, но прошу прощения, если я пропустил их.

+0

Именование в порядке, я мог бы запустить его с помощью вставки только :). В любом случае, я думаю, стоит отметить, что вы передаете право собственности на другой этап и другим способом: путем изменения потока вручную. Таким образом, дело не в том, что владение элементами управления может оставаться с формой, а скорее вам не нужно его менять * сначала *. Как и вы, это не критика, просто хотелось бы отметить это. –

+0

Да, хороший момент. – Dsm

+0

Nice Sertac! Только один вопрос: после загрузки pnlSource в pnlTarget это последнее становится pnlSource; это правильно? – Eros