Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Основная";
Текущий архив: 2006.05.07;
Скачать: [xml.tar.bz2];

Вниз

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

 
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;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.51 MB
Время: 0.013 c
15-1144997405
syte_ser78
2006-04-14 10:50
2006.05.07
вопрос по работе со временем.


15-1144829483
boriskb
2006-04-12 12:11
2006.05.07
Как вам американский "Солярис"?


2-1145516103
Zaq123
2006-04-20 10:55
2006.05.07
Проблема с записью в файл.


15-1144826480
syte_ser78
2006-04-12 11:21
2006.05.07
Ваши юношеские заблуждения (компьютерные)


3-1141962120
кораблик
2006-03-10 06:42
2006.05.07
Помогите разобраться с DBLookupComboBox





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский