Форум: "Основная";
Текущий архив: 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.52 MB
Время: 0.011 c