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

Вниз

Сохранение компонентов в файл и чтение из него   Найти похожие ветки 

 
DmitryNekl   (2004-07-19 18:07) [0]

Добрый день. Не знаю, может, мне в БД надо... В общем, вопрос такой:

Создаю форму:
procedure TForm1.FormCreate(Sender: TObject);
begin
 ADOConnection1:=TADOConnection.Create(self);
 ADOConnection1.Name:="ADOConnection1";
 ADOConnection1.LoginPrompt:=False;
 ADOConnection1.ConnectionString:="...";
 ADOConnection1.GetTableNames(Combobox1.Items, False);

 ADOQuery1:=TADOQuery.Create(self);
 ADOQuery1.Connection:=ADOConnection1;

 DataSource1:=TDataSource.Create(self);
 DataSource1.Name:="DataSource1";
 DataSource1.DataSet:=ADOQuery1;

 DBGrid1:=TDBGrid.Create(Form1);
 DBGrid1.Name:="DBGrid1";
 DBGrid1.Parent:=Form1;
 DBGrid1.DataSource:=DataSource1;
end;


Потом что-то делаю с ней, и в гриде отображаются какие-то данные. После этого сохраняю компоненты в файл:

procedure TForm1.Button6Click(Sender: TObject); // сохраняем табличку в файл
begin
 ADOConnection1.Name:="";
 WriteComponentResFile("ADOConnection1.dfm", ADOConnection1);
 ADOConnection1.Name:="ADOConnection1";

 ADOQuery1.Name:="";
 WriteComponentResFile("ADOQuery1.dfm", ADOQuery1);
 ADOQuery1.Name:="ADOQuery1";

 DataSource1.Name:="";
 WriteComponentResFile("DataSource1", DataSource1);
 DataSource1.Name:="DataSource1";

 DBGrid1.Name:="";
 WriteComponentResFile("DBGrid1.dfm", DBGrid1);
 DBGrid1.Name:="DBGrid1";
end;


А потом пытаюсь прочесть из файла (в другую форму, чистую):
procedure TForm1.Button7Click(Sender: TObject);
var F: TForm;
begin
 F:=TForm4.Create(Form1);
end;


constructor TForm4.Create(AOwner: TComponent); // override;
var
 fname: String;
begin
   RegisterClasses([TADOQuery, TADOConnection, TDBGrid, TDataSource, TForm4, TButton]);
   CreateNew(AOwner);
   ReadComponentResFile("ADOConnection1.dfm", Self);
   ReadComponentResFile("ADOQuery1.dfm", Self);
   ReadComponentResFile("ADODataSource1.dfm", Self);
   ReadComponentResFile("DBGrid1.dfm", Self);
   Self.Name:="";
   Self.Caption:="...";
   Self.Show;
end;


и получаю ошибку "Property Connected does not exist"...

Как бороться? Заранее спасибо!


 
Defunct ©   (2004-07-20 03:29) [1]

Что-то я вопрос не понял...

что надо сохранить?


 
DmitryNekl   (2004-07-20 09:09) [2]

Исходно задача такая. Пишу приложение для работы с БД. Хочу сделать максимально гибко настраиваемым.

В частности, можно сделать так: настроить все поля в редакторе полей, визуально сформировать соответствующий грид (чтобы названия колонок по-русски отображались и т.д.). Но тогда мы жестко привязываемся к структуре таблиц базы.

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

Вот, собственно, и пытаюсь сначала сохранить, а потом - восстановить...


 
Sun bittern ©   (2004-07-20 09:09) [3]

WriteComponent не сохраняет указатели на внешние компоненты.


 
DmitryNekl   (2004-07-20 09:17) [4]

А как это можно реализовать?


 
Sun bittern ©   (2004-07-20 09:23) [5]

А, ветку на пенсию уже отправели. Ищи сайт TDElphi (адрес непомню) и на этом сайте ищи компоненты LMDTools (там говорят дезайнер есть, но еще не смотрел, можещь тпм реализацию глянуть). Ну или этот же пакет ищи гденибудь в другом месте.


 
DmitryNekl   (2004-07-20 10:28) [6]

В общем, научился я сохранять и загружать:

Сохранение:
 f := TFileStream.Create("c:\stream.vcl", fmCreate);
 f.WriteComponent(DBGrid1);  
 f.Free;

Загрузка:
   f := TFileStream.Create("c:\stream.vcl", fmOpenRead);
   f.ReadComponent(DBGrid1);
   f.Free;

Все работает, но интересный глюк (или я чего не понимаю):

Есть исходная форма, на которой расположен этот самый грид. Я его сохраняю в файл и потом загружаю на другую форму. В момент загрузки этот грид с первой формы исчезает :(.

С чем это может быть связано и как, собственно, бороться?


 
Sun bittern ©   (2004-07-20 11:08) [7]

>> f.ReadComponent(DBGrid1);

Form2 := TForm(f.ReadComponent(DBGrid1));
Может так?


 
DmitryNekl   (2004-07-20 11:16) [8]

А почему так? Я код не полностью привел, на самом деле в конструкторе второй формы делаю так:
   RegisterClasses([TADOQuery, TADOConnection, TDBGrid, TDataSource, TForm4, TButton]);
   CreateNew(AOwner);
   f:=TFileStream.Create("c:\stream.vcl", fmOpenRead);
   f.ReadComponent(DBGrid1);
   f.Free;
   DBGrid1.Align:=alClient;
   DBGrid1.Parent:=Self;
   DBGrid1.Visible:=True;

У меня вопрос, в общем-то - почему исчезает грид с первой формы???


 
Sun bittern ©   (2004-07-20 11:37) [9]

var
   FS: TFileStream;
   A: TComponent;
begin
 FS := TFileStream.Create("Nova.dfa", fmOpenRead or fmShareDenyRead);
 try
   A := FS.ReadComponent(nil);
   if A is TControl then
     TControl(A).Parent := Form2;
 finally
   FS.Free;
 end;
end;


 
DmitryNekl   (2004-07-20 11:53) [10]

Спасибо, все заработало! :)
Хотя я и не понимаю, почему :).

Можно ссылочку на какую-нить статью на эту тему?


 
Sun bittern ©   (2004-07-20 12:14) [11]

>> Хотя я и не понимаю, почему :).

FS.ReadComponent(nil);

А гдето в инете давно данный пример откопал. Возможно на королевстве дельфи.
Кстати
  DBGrid1.Align:=alClient;
  DBGrid1.Parent:=Self;
  DBGrid1.Visible:=True;

Данные Published свойства (те что видны в инспекторе объектво) сохраняются WriteComponent (кроме, как я описал выше линек на внешние компоненты) и изменять необязательно. В данном случае Parent не Published свойство, вот и портебовалось указать ему родителя.


 
DmitryNekl   (2004-07-20 13:10) [12]

Нашел еще неприятную особенность... в качестве всяких ADOQuery, ADOConnection при загрузке формы используются те, которые находятся на форме, с которой происходит сохранение грида.

Как бы мне вместе с гридом сохранять и компоненты ADOQuery, ADOConnection, DataSource, а при загрузке грида загружать и их и подключать к гриду?


 
Sun bittern ©   (2004-07-20 13:29) [13]

Может тебе не кусками сохранять, а всю форму в поток слхранить? Как этот вариант?


 
DmitryNekl   (2004-07-20 14:07) [14]

Да, это я умею... но тут прикол в том, что редактирую я все это дело в одной форме, а открываю настроенный грид - в другой. А в первой всяких "лишних" наворотов до дури...


 
Sun bittern ©   (2004-07-20 14:10) [15]

Ты свой мини дизайнер создаешь чтоли :)


 
DmitryNekl   (2004-07-20 14:15) [16]

Не совсем... но стало близко к нему :)

Изначально я делал приложение для работы с БД, но структура БД стала меняться слишком часто... в общем, я решил, что это оптимально :). И в принципе, сделал... осталось тока научиться сохранять/загружать...

А по существу есть мысли?


 
Sun bittern ©   (2004-07-20 16:59) [17]

>> А в первой всяких "лишних" наворотов до дури...

1. Дурь можно вынести на отдельную форму - яля панель инструментов
2. Или. Кинуть нужные компоненты на отдельный TWinControl (например TPanel). Тоесть точто нужно сохранить просаем на эту панельку. Но чтобы вместе с этой панелькой сохранились и компоненты наней, лежащие на ней компоненты должны пренадлежать ей т.е. она должна являться хозяином для них (Owner). Далее сохранить панель в файл (указать только панель, раз для компонентов хозяином является панель, то то что на ней автоматически сохранится в файл)
3. Ну можно еще чего насоченять ;)


 
DmitryNekl   (2004-07-20 18:04) [18]

О, классная мысль (про панельку)! :)
Непременно попробую, спасибо огромное! :)


 
DmitryNekl   (2004-07-21 10:17) [19]

Хрень какая-то... Не работает. Т.е.:

procedure TForm1.FormCreate(Sender: TObject);
begin
 Panel1:=TPanel.Create(Form1);
 Panel1.Parent:=Form1;

 ADOConnection1:=TADOConnection.Create(Panel1);
 ADOConnection1.Name:="ADOConnection1";
 ADOConnection1.LoginPrompt:=False;
 ADOConnection1.ConnectionString:="...";

 ...

 ADOQuery1:=TADOQuery.Create(Panel1);
 ADOQuery1.Connection:=ADOConnection1;

 DataSource1:=TDataSource.Create(Panel1);
 DataSource1.Name:="DataSource1";
 DataSource1.DataSet:=ADOQuery1;

 DBGrid1:=TDBGrid.Create(Panel1);
 DBGrid1.Name:="DBGrid1";
 DBGrid1.Align:=alClient;
 DBGrid1.DataSource:=DataSource1;
 DBGrid1.Parent:=Panel1;
end;


Потом выбираю таблицу БД, грид загружается данными... Сохраняю:

procedure TForm1.Button6Click(Sender: TObject);
var f: TFileStream;
begin
 f := TFileStream.Create("c:\stream1.vcl", fmCreate);
 f.WriteComponent(Panel1);
 f.Free;
end;


Потом читаю в другой форме:

constructor TForm4.Create(AOwner: TComponent);
var
 fname: String;
 FS: TFileStream;
 a1, a2, a3, a4: TComponent;
begin
 RegisterClasses([TPanel, TADOQuery, TADOConnection, TDBGrid, TDataSource, TForm4, TButton]);
 CreateNew(AOwner);
 FS := TFileStream.Create("c:\stream1.vcl", fmOpenRead or fmShareDenyRead);
 try
   A4 := FS.ReadComponent(nil);
   if A4 is TControl then
   begin
     TControl(A4).Parent := Self;
     TControl(A4).Align :=alClient;
   end;
 finally
   FS.Free;
 end;
end;


Форма появляется, на ней - панелька, на панельке - грид, но грид к таблице не подключен, а пустой :(

Почему? Что делать?


 
Sun bittern ©   (2004-07-21 10:59) [20]

Я же тебе писал WriteComponent не сохраняет указатели на внешние компоненты и методы (события). Ковыряйся в компонентах с исходниками может там нароешь.
Sun bittern ©   (20.07.04 09:23) [5]
Я начинал делать парсер строк для определения ссылки на компоненты и методы используя RTTI но до конца пока не доделал.

Сайт http://www.tdelphi.spb.ru/ раздел компоненты


 
DmitryNekl   (2004-07-21 11:13) [21]

Что-то я не пойму. Я сохраняю панель, которая является owner-ом для:
1. DBGrid
2. ADOConnection
3. ADOQuery
4. DataSource
Вместе с панелью сохраняется грид... почему же не сохраняется все остальное? Где тут внешние компоненты?


 
Sun bittern ©   (2004-07-21 11:33) [22]

TDBGrid.DataSourece := MyDataSource

Вот MyDataSource и не сохранится в свойстве DataSourece компонента TDBGrid. Также как к примеру и TPopupMenu в свойстве PopupMenu компонента TPanel.


 
Sun bittern ©   (2004-07-21 11:52) [23]

Точнее наверно будет сказать так:

В свойстве DataSourece компонента TDBGrid не сохранится указатель на компонент MyDataSource.


 
DmitryNekl   (2004-07-21 12:00) [24]

А еще интересный вопрос. После выхода из конструктора как мне до мой панельки или до грида добраться? Self.ComponentCount выдает 0 (последним оператором в конструкторе)...


 
DmitryNekl   (2004-07-21 12:03) [25]

Sun bittern ©   (21.07.04 11:52) [23]
Точнее наверно будет сказать так:
В свойстве DataSourece компонента TDBGrid не сохранится указатель на компонент MyDataSource.

Я правильно понимаю, что все 4 компонента вместе с панелью сохранились, и достаточно настроить их взаимные связи? Тока вот добраться бы до них :)


 
Sun bittern ©   (2004-07-21 12:10) [26]

Self это форма? Если для компонент Owner панелька, то это действительно должно быть так.


 
Sun bittern ©   (2004-07-21 12:15) [27]

>> 4 компонента вместе с панелью сохранились

Если Owner у них панелька, то должны вместе сней в файл слиться.


 
DmitryNekl   (2004-07-21 12:16) [28]

Да, в конструкторе формы Self - это форма. Для компонент Owner - действительно панелька. НО! КАК МНЕ ДОБРАТЬСЯ ДО КОМПОНЕНТОВ, чтобы настроить их свойства?


 
Sun bittern ©   (2004-07-21 12:24) [29]

Дык. Чей Owner у компонент, у того вроде и надо спрашивать. А у кого? Можешь узнать например так, псоле загрузки: DataSource1.Owner.Name


 
DmitryNekl   (2004-07-21 14:17) [30]

Ничего не понимаю... в конструктор добавил:


(Panel1.Components[1] as TADOQuery).Connection:=(Panel1.Components[0] as TADOConnection);
(Panel1.Components[2] as TDataSource).DataSet:=(Panel1.Components[1] as TADOQuery);
(Panel1.Components[3] as TDBGrid).DataSource:=(Panel1.Components[2] as TDataSource);


Все работает (сообщений об ошибках нет), но грид выводится пустой...


 
Sun bittern ©   (2004-07-21 15:13) [31]

>> Panel1.Components[2] as TDataSource

От куда такая уверенность? Индексы могут ведь и поменяться со временем.

P.S. Можешь свой проект на мыло мне кинуть. Только без *.dcu, *.exe, *.~* и другого мусора.


 
DmitryNekl   (2004-07-21 15:27) [32]

С одной стороны, могу, а с другой - это бесполезно, ибо к базе я подключаюсь в инете (MySQL), и тебе придется настроить источники данных и т.д.

Уверенность - я проверил один раз... если бы что-то изменилось, была бы ошибка приведения типов, а ее не происходит.


 
Sun bittern ©   (2004-07-21 15:36) [33]

DmitryNekl   (21.07.04 15:27) [32]

Может компонентам адошным и таблицам надо в проперти Active в True принудительно указать?


 
Sun bittern ©   (2004-07-21 15:41) [34]

DmitryNekl   (21.07.04 15:27) [32]

после загрузки проверь открыты ли у тебя источники данных (Active = True)


 
DmitryNekl   (2004-07-21 15:45) [35]

Пробовал... однако торможу.
Смотри, фигня какая. Привожу еще раз код:

Создание компонентов на первой форме:

procedure TForm1.FormCreate(Sender: TObject);
begin
 Panel1:=TPanel.Create(Form1);
 Panel1.Name:="Panel1";
 Panel1.Left:=20;
 Panel1.Width:=Form1.Width-40;
 Panel1.Top:=320;
 Panel1.Height:=Form1.Height div 4;
 Panel1.Parent:=Form1;

 ADOConnection1:=TADOConnection.Create(Panel1);
 ADOConnection1.Name:="ADOConnection1";
 ADOConnection1.LoginPrompt:=False;
 ADOConnection1.ConnectionString:="...";

 ADOQuery1:=TADOQuery.Create(Panel1);
 ADOQuery1.Connection:=ADOConnection1;

 DataSource1:=TDataSource.Create(Panel1);
 DataSource1.Name:="DataSource1";
 DataSource1.DataSet:=ADOQuery1;

 DBGrid1:=TDBGrid.Create(Panel1);
 DBGrid1.Name:="DBGrid1";
 DBGrid1.Align:=alClient;
 DBGrid1.DataSource:=DataSource1;
 DBGrid1.Parent:=Panel1;
end;


Код создания второй формы:

constructor TForm4.Create(AOwner: TComponent); // override;
var
 i: integer;
 fname: String;
 FS: TFileStream;
 a4: TComponent;
begin
 RegisterClasses([TPanel, TADOQuery, TADOConnection, TDBGrid, TDataSource, TForm4, TButton]);
 CreateNew(AOwner);
 FS := TFileStream.Create("c:\stream1.vcl", fmOpenRead or fmShareDenyRead);
 try
   A4 := FS.ReadComponent(nil);
   if A4 is TControl then
   begin
     TControl(A4).Parent:=Self;
     TControl(A4).Align:=alClient;
   end;
 finally
   FS.Free;
 end;

 ShowMessage(Panel1.Parent.ClassName);

 (Panel1.Components[1] as TADOQuery).Connection:=(Panel1.Components[0] as TADOConnection);
 (Panel1.Components[2] as TDataSource).DataSet:=(Panel1.Components[1] as TADOQuery);
 (Panel1.Components[3] as TDBGrid).DataSource:=(Panel1.Components[2] as TDataSource);

 Self.Name:="";
 Self.Caption:="Редактирование содержимого таблицы";
 Self.Show;
end;

То, что жирным выделено, до меня дошло вставить туда только что... Выводит Form1, т.е. я играю не с тем объектом.

А оператор
for i:=0 to TControl(A4).ComponentCount-1 do ShowMessage  (TControl(A4).Components[i].ClassName);
вставленный вместо жирного, выводит только TDBGrid... и больше нифига. Это получается, что остальные три объекта не сохраняются вместе с панелькой?


 
Sun bittern ©   (2004-07-21 16:30) [36]

Блин. Выходит, что сохраняются только TControl :^( Щас сам проверил.


 
DmitryNekl   (2004-07-21 16:33) [37]

И что теперь делать? Что ли, сохранять каждый компонент по отдельности и загружать на форму, а потом настраивать связи?


 
Sun bittern ©   (2004-07-21 16:49) [38]

Не знаю поможет ли
http://delphimaster.net/view/5-1089284149/

Как второй извращщенный вариант :(
Поместить не визуальные компоненты в DataModule (для удобства)
Визуальным компонентам назначить уникальный Tag. Полсле загрузки панельки перебрать на ней контролы и проверять Tag. Например если 1, то ага, значит у тебя есть проперти DataSource и назначить ему соотвествующий DataSource из DataModule.

Но это все изврат и неудобно в дальнейшем расширять функциональность. Лучше скачать пакет компонент Sun bittern ©   (20.07.04 09:23) [5] и посомтреть как это профи сделали. Или создавать парсер строк (по типу *.dfm файла) с помощью RTTI.


 
DmitryNekl   (2004-07-21 17:34) [39]

Извращенный вариант не пройдет: смысл именно в том, чтобы сохранять все изменения в составе и описаниях полей и т.д.

А насчет поможет ли - посмотрим... Боюсь, кода профи я не пойму... не настолько глубоко все знаю. :(

Будем учиться :)



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

Форум: "Основная";
Текущий архив: 2004.08.01;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.63 MB
Время: 0.038 c
6-1085987739
Maxuz
2004-05-31 11:15
2004.08.01
Работа с весовым терминалом через TCP/IP


4-1087382966
Leon
2004-06-16 14:49
2004.08.01
Можно ли послать сообщение WM_CLOSE и не ждать


1-1089890578
_Dragon
2004-07-15 15:22
2004.08.01
Проблема с Listbox в runtime


1-1090395219
миня
2004-07-21 11:33
2004.08.01
как узнать длину строки?


14-1089857133
Думкин
2004-07-15 06:05
2004.08.01
С днем рождения! 15 июля





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
Английский Французский Немецкий Итальянский Португальский Русский Испанский