Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2006.05.07;
Скачать: CL | DM;

Вниз

Сохранение компонета   Найти похожие ветки 

 
Yegorchic ©   (2006-03-22 23:38) [0]

Здравствуйте! Не подскажите, как можно "сохранить" компонент (записать в переменную типа string, например)? Т.е. как он в .dfm записывается - так же.


 
Джо ©   (2006-03-23 01:04) [1]

TStream.WriteComponent
+
ObjectBinaryToText


 
Джо ©   (2006-03-23 01:09) [2]

В таком, примерно, духе:

function ComponentToText (AComponent: TComponent): string;
var
 BinaryStream: TMemoryStream;
 StringStream: TStringStream;
begin
 BinaryStream := TMemoryStream.Create;
 try
   BinaryStream.WriteComponent(AComponent);
   StringStream := TStringStream.Create("");
   try
     BinaryStream.Position := 0;
     ObjectBinaryToText(BinaryStream,StringStream);
     Result := StringStream.DataString;
   finally
     StringStream.Free;
   end;
 finally
   BinaryStream.Free;
 end;
end;


Использование:
procedure TForm1.Button1Click(Sender: TObject);
begin
 ShowMessage(ComponentToText(Self));
end;


 
TUser ©   (2006-03-23 07:05) [3]

Есть еще компонент TJvFormStorage - позволяет сохранять (и загружать) свойства компонентов в ini файл или реестр.


 
Yegorchic ©   (2006-03-23 11:55) [4]

Класс!!! Спасибо большое!!!


 
Yegorchic ©   (2006-03-27 23:05) [5]

А теперь возник немного другой вопрос: как "открыть" компонент? Надо использовать ReadComponent что-ли? Я чего-то запутался...


 
Yegorchic ©   (2006-03-28 19:03) [6]

Подскажите пожалуйста!
Я делаю так:

1. Сначала пишу тексте в StringStream (ну до этого создаю естественно всё):

StringStream.WriteString(text);

2. Потом использую ObjectTextToBinary:

ObjectTextToBinary(StringStream, BinaryStream);

3. И потом делаю так, что бы записать всё это дело назад в компонент:

result:=BinaryStream.ReadComponent(AComponent);

В Run-Time при открытии вылезает ошибка:

EParserError: "OBJECT expected on line 1"

Что такое?


 
Джо ©   (2006-03-28 19:31) [7]

procedure ReadComponentPropertiesFromText (AComponent: TComponent; AText: string);
var
 BinaryStream: TMemoryStream;
 StringStream: TStringStream;
begin
 StringStream := TStringStream.Create(AText);
 try
   BinaryStream := TMemoryStream.Create;
   try
     ObjectTextToBinary(StringStream,BinaryStream);
     BinaryStream.Position := 0;
     BinaryStream.ReadComponent(AComponent);
   finally
     BinaryStream.Free;
   end;
 finally
   StringStream.Free;
 end;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
 S: string;
begin
 S := ComponentToText(Button1);
 ShowMessage(S);
 ReadComponentPropertiesFromText(Button1,S);
end;


Но все это не так просто, как может показаться...


 
Yegorchic ©   (2006-03-28 20:04) [8]

Спасибо!

Т.е. функция BinaryStream.ReadComponent(AComponent) сразу записывает все параметры в компонент? А зачем тогда она ещё может возвращать TComponent?


 
Джо ©   (2006-03-28 20:14) [9]

> [8] Yegorchic ©   (28.03.06 20:04)
> А зачем тогда она
> ещё может возвращать TComponent?

Затем, что в качестве параметра для (AComponent) ты можешь задать nil. В этом случае класс компонента будет прочитан из потока, функция создаст компонент этого класса и возвратит его. Если же параметр не будет nil, то функция просто его возвратит. В общем, смотри исходники, в частности, метод TReader.ReadRootComponent(Root: TComponent): TComponent (Classes.pas):


     if Root = nil then
     begin
       Result := TComponentClass(FindClass(ReadStr)).Create(nil);
       Result.Name := ReadStr;
     end else
     begin
       Result := Root;
       ...
     end;



 
Yegorchic ©   (2006-03-28 20:19) [10]

Вроде понял!!! Спасибо большое!!! Теперь у меня всё работает!!!


 
Yegorchic ©   (2006-03-28 21:56) [11]

Нет, не совсем ещё всё работает.
Компоненты, которые я, читая из файла, создавал в Run-Time - все хорошо создаются и работают.

Но тут мне пришлось сохранить компонент, который я создал в Design-Time - он сохранился. Но когда я его стал открывать, то мне вылезла ошибка о том, что компонент с таким именем уже существует! Как же тут быть?

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

Я вот что-то сбился: функция BinaryStream.ReadComponent(AComponent) не должна создавать новый компонент, она должна же изменить AComponent! Почему так происходит-то? И судя по примеру, который Вы привели в [7] такого быть не должно!


 
Джо ©   (2006-03-28 23:09) [12]

> [11] Yegorchic ©   (28.03.06 21:56)
> Вы случайно не эту проблему имели ввиду, когда писали:
> "Но все это не так просто, как может показаться..."

Это. В том числе.


> Я вот что-то сбился: функция BinaryStream.ReadComponent(AComponent)
> не должна создавать новый компонент, она должна же изменить
> AComponent!

Представь такую ситуацию. Сериализуешь ты форму, а на ней лежит, допустим, кнопка. Когда ты опять пытаешься десериализовать эту форму из потока, он пытается создать и кнопку, лежащую на ней. И задает ей имя, то, которое уже есть. Т.е:
procedure TForm1.Button1Click(Sender: TObject);
var
 S: string;
begin
 S := ComponentToText(Self);
 ShowMessage(S); // посмотри внимательно на текст.
 ReadComponentPropertiesFromText(Self,S);
end;

приведет к исключению "A component named Button1 already exists".


 
Yegorchic ©   (2006-03-28 23:36) [13]

Да, это я понял, но что тогда в таком случае делать? Мне надо сохранить в файл все свойства обеъкта (TEdit, например), а потом их "открыть". Edit уже создан и что тогда делать?


 
Yegorchic ©   (2006-03-28 23:39) [14]

А хотя я вроде понял...


 
Yegorchic ©   (2006-03-29 14:47) [15]

Нет, всё так и не работает. Мне так и не удалось реализовать [13] :(


 
Джо ©   (2006-03-29 17:08) [16]

Честно говоря, не совсем, видимо, понял, чего нужно добиться.

Вот так же работает?
procedure TForm1.Button1Click(Sender: TObject);
var
 S: string;
begin
 // "запоминаем" состояние компонента
 S := ComponentToText(Edit1);
 // изменяем его
 Edit1.Text := "123";
 // пауза
 Repaint;
 Sleep (1000);

 // восстанавливаем
 ReadComponentPropertiesFromText(Edit1,S);
end;


 
Yegorchic ©   (2006-03-29 17:45) [17]

Ну да, это работает.
Может, проблема в том, что у меня в сохраняемом компоненте есть другие компоненты? Но в ошибки при открытии ничего о них не говорится...


 
Джо ©   (2006-03-29 17:58) [18]

Приведи конкретный код, который ты хочешь сделать рабочим, а то так и будем вокруг да около топтаться :-)


 
Yegorchic ©   (2006-03-29 19:02) [19]

Код не очень маленький, и может показаться Вам немного странным :-)

Дело в том, что я пишу небольшую программу с использованием GLScene (наверное знаете - оболочка, так сказать, для OpenGL). В процессе работы с программой требуется сохранить саму сцену со всеми объектами на ней (конечно, в GLScene предусмотрена функция сохранения сцены, но она плохо сделана (это не только моё мнение) - поэтому пришлось писать самому).
Сама сцена при старте программы пустая - присутствуют только две камеры (созданные как раз в Design-Time). Во время работы с программой на этой сцене создаются объекты (в RunTime, естественно).
Когда дело доходит до сохранения, то я сохраняю все объекты созданные в Run-Time + те самые 2 камеры - всё сохраняется. Как дело доходит до открытия сцены (программа уже перезапущена, естественно), то все объекты созданные в Run-Time очень хорошо и правильно открываются, но когда дело доходит до тех двух камер - программа выдаёт ту самую ошибку о том, что такое объект уже существует!
Да, чуть не забыл сказать - в одной из камер находится источник света (ну он тоже как компонент). Но он тут не причём я думаю.

Да, действительно такие объекты (эти две камеры) уже существуют, но при использовнии фунции BinaryStream.ReadComponent(), если параметр не nil, должен просто измениться компонент, а не создаваться новый! Такое же не происходит с TEdit"ом, например!


 
Yegorchic ©   (2006-03-29 20:57) [20]

Джо, кажется почти мне стало ясно в чём дело: у меня же две камеры - в одной есть источник света (ну как компонент), и эта камера "открывалась" первой. На этом месте, соответственно, процесс открытия остановился.
Я решил оставить для открытия только одну камеру - вторую, в которой ничего нет. Она открылась. Т.е. те компоненты, у которых нет child"ов - хорошо открываются.

Что же тогда делать с компонентами, которые принадлежат ещё какие-то компоненты - они не открываются!


 
Старик   (2006-03-30 09:10) [21]

Yegorchic:
>>Что же тогда делать с компонентами, которые принадлежат ещё какие-то компоненты - они не открываются!

Ясно, что делать. Смотрим, есть ли у этого компонента другие, принадлежащие к нему, и если есть, то их сохраняем тем же макаром.
Обычно за это отвечает свойство Parent/Owner.
Свойство Owner у некоторого компонента обычно заявляет о том, что этот компонент просто ЛЕЖИТ на другом компоненте - например, метка на TPanel. Свойство Parent обычно заявляет о том, что компонент с этим свойством создается родительским компонентом (обозначенным в свойстве Parent) и им же убивается. Так что делаем следующим образом:
Сохраняем главный компонент. Затем ищем все компоненты, у которых в свойстве Parent проставлен главный компонент, и тоже их сохраняем.

P.S.: Писал на скорую руку, возможны ошибки. Если что, поправьте меня.


 
Yegorchic ©   (2006-03-30 14:09) [22]


> Сохраняем главный компонент. Затем ищем все компоненты,
> у которых в свойстве Parent проставлен главный компонент,
>  и тоже их сохраняем.


Да, но когда я сохраняю главный компонент - все компоненты, которые принадлежат ему сохраняются вместе с ним! Или может я чего-то не понимаю... :\



Страницы: 1 вся ветка

Текущий архив: 2006.05.07;
Скачать: CL | DM;

Наверх




Память: 0.53 MB
Время: 0.039 c
15-1145095256
SergP.
2006-04-15 14:00
2006.05.07
Нужна помощь по скачиванию файла


2-1145271528
ttt_111
2006-04-17 14:58
2006.05.07
Как сделать отчет?


2-1144903632
paul_k
2006-04-13 08:47
2006.05.07
Не могу понять. Или у меня руки кривые или одно из двух.


15-1145002581
data
2006-04-14 12:16
2006.05.07
Ежегодное приглашение))


15-1145020496
default
2006-04-14 17:14
2006.05.07
Перевод mp3 в mmf