Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Базы данных и репортинг > DataModule & MDI


Автор: santilaas 30.4.2006, 07:54
Firebird1.5, FibPlus5.2
У меня такой вопрос:
Создаю MDI - приложение. Имеется форма Main (fsMDIForm), форма Child (fsMDIChild) и DataModule (на нём есть DataSet и связанный с ним DataSource).
Притом форма Child создаётся динамически (в опциях проекта она находится в столбце "Доступные формы") и открывается из главной формы следующим образом:
Код

Child:=TChild.Create(self);
Child.Show;

На форме Child имеется DBGridEh (связанный с DataSource) и поле Memo. Да, и кстати DataSet активизирую при событии OnCreate формы Child.

Мне нужно, чтобы при переходе по записям в DBGridEh-е в поле Memo отображалось текущее значение. Для этого я в DataModule на события OnDataChange и OnStateChange (компонента DataSource) пишу одинаковый код:
Код

name:= DataModule.DataSetNAME.AsString;
Child.Memo.Lines.Clear;
Child.Memo.Lines.Add(name);


Компилирую, запускаю, открываю эту форму и ... ошибка адреса ("Read of address 00000350"). 
Когда запускаю этот откомпилированный exe-шник, опять же выводится сообщение об ошибке - я его закрываю и все работает как надо (при переходе по записям все изменения-перемещения ображаются в Memo).

Что интересно: если при таком же раскладе помещаю Child в опциях проекта в столбец "Автоматически создавать", 
то все работает, но эта дочерняя форма открывается вместе с Main формой - что совсем не то, что мне нужно.

Помогите, люди добрые, что не так???? Мож чего дописать в обработчиках OnDataChange и OnStateChange????
Заранее спасибо, всем, даже тем кто все это прочитает! 

Автор: Vas 30.4.2006, 09:12
Цитата(santilaas @  30.4.2006,  07:54 Найти цитируемый пост)
Да, и кстати DataSet активизирую при событии OnCreate формы Child.

Активируй его в onShow формы, а если  в onCreate, то первой строкой поставить inherited. 

Автор: santilaas 30.4.2006, 14:16
Vas, когда активирую Датасет в onShow ситуация такая же - ошибка адреса.

А насчет inherited - можно поподробнее, плз - что за строку надо ставить впереди?  

Автор: Vas 1.5.2006, 07:03
Цитата(santilaas @  30.4.2006,  07:54 Найти цитируемый пост)

Child:=TChild.Create(self);
Child.Show;


В этом коде Child.Show убери для MDI-окон это не надо, еси MDI-окно создано то оно автоматически становится видимым. А строчка inherited в onCreate позволяет сначала выполнить свой код компоненту, а только потом выполнять то что написано после  этой строки в конструкторе.  

Автор: santilaas 1.5.2006, 08:04
Vas, это снова я
При создании дочерней формы пишу:
Код

procedure TChild.FormCreate(Sender: TObject);
begin
   inherited;  //пробовал ещё inherited Create(owner);
   DataModule.DataSet.Active:= True;
end; 
 - но ошибка та же. Наверное, не то пишу - если не трудно, поправь меня.   

Автор: Vas 1.5.2006, 13:28
Цитата(santilaas @  1.5.2006,  08:04 Найти цитируемый пост)
Vas, это снова я
При создании дочерней формы пишу:
Код

procedure TChild.FormCreate(Sender: TObject);
begin
   inherited;  //пробовал ещё inherited Create(owner);
   DataModule.DataSet.Active:= True;
end; 

- но ошибка та же. Наверное, не то пишу - если не трудно, поправь меня.    


Ну все верно! Странно что ошибка лезет, а отладчиком не пробовал ее отловить? Попробуй еще заменить Memo на DBMemo ну и связать его с твоим DataSet'ом как полагается. Просто очень странно что когда форма создается автоматом ошибки нет, а когда не автоматом есть  smile  

Автор: santilaas 3.5.2006, 13:56
В общем эта проблема решена (благодаря одному очень хорошему человеку):
надо просто открывать дочернюю форму следующим образом:
Код

   Child:=TChild.Create(self);
   DataModule.DataSet.Active:= True;


НО!!! Тут возникла другая проблема - данные в ДБГриде появляются с некоторой задержкой. Я пробовал в этом коде (см. выше) поменять строки местами (т.е сначала активизирую DataSet, а затем делаю Create) и всё стало нормально для всех форм (у меня их много), кроме той (Child), она при таком раскладе выдаёт всё ту же ошибку адреса. Меняю строки обратно - все нормально, но ... тормоза при открытии. 

В чём проблема - вернее как её решить???? 

Автор: vv3 5.5.2006, 23:36
Цитата(santilaas @  30.4.2006,  07:54 Найти цитируемый пост)
name:= DataModule.DataSetNAME.AsString;
Child.Memo.Lines.Clear;

Ну, когда ты делаешь это до TChild.Create, то ошибка будет, как ни крути, поскольку Child'a еще нету...
"Тормоза при открытии", как подсказывает логика, возникают не за счет указанного порядка. Просто запрос отрабатывает долго. 
Вариант решения: попробуй вынести заполнение Memo в обработчик DataSet.AfterScroll, а заодно и Child.Create туда же:
Код

begin
if not Assigned(Child) then Child:= TChild.Create(Application);
name:= DataModule.DataSetNAME.AsString;
Child.Memo.Lines.Clear;
//далее по тексту...
end;
  

Автор: santilaas 14.5.2006, 10:31
Цитата

В общем эта проблема решена (благодаря одному очень хорошему человеку):
надо просто открывать дочернюю форму следующим образом:
Код

  Child:=TChild.Create(self);
   DataModule.DataSet.Active:= True;

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

НО!!!
Новая проблема или не совсем проблема, но в любом случае меня это не устраивает:
Обрисую ситуацию заново:
Есть форма - на ней 2 таблицы (мастер (DataSet1, DataSource1, DBGridEh1) и деталь(DataSet2, DataSource2, DBGridEh2) - она, кстати, открывается при нажатии на кнопку "Деталь") и поле Memo, в которое должно выводиться значение, заданное в onDataChange для той таблицы, на которой указатель.
в onDataChange мастер таблицы пишу:
Код

//переменные master и detal объявлены как глобальные
   master:= DataModule.DataSet1.AsString;
   FChild.Memo.Lines.Clear;
   FChild.Memo.Lines.Add(master);

в onDataChange деталь таблицы пишу:
Код

   detal:= DataModule.DataSet2.AsString + '/' + DataModule.DataSet1.AsString;
   //или detal:= DataModule.DataSet2.AsString + '/' + master;
   FChild.Memo.Lines.Clear;
   FChild.Memo.Lines.Add(detal);

При нажатии на кнопку "Деталь" устанавливаю фокус на DBGridEh2:
Код
DBGridEh2.SetFocus;

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

Например, в мастер таблице две записи: "Полка1" (для неё в деталь деталь - таблице: "Книга1","Книга2","Книга3") и "Полка2".
Когда я в мастер-таблице при скроллинге попадаю на запись "Полка1", у меня в Memo отображается "Полка1", но чисто визуально может мелькнуть и "Полка1/Книга1".

Как этого избежать??? smile  - а то уже хочу отказаться от скроллинга и просто выбирать нужное значение простым Click-ом (так ничего не мелькает) 

Автор: vv3 14.5.2006, 19:57
Код

procedure MasterDataset1BeforeScroll(Dataset: TDataset);
begin
Dataset.DisableControls;
end;

procedure MasterDataset1AfterScroll(Dataset: TDataset);
begin
Dataset.EnableControls;
end;
 

Автор: santilaas 15.5.2006, 11:17
vv3, попробовал я - покрутил и так и этак, но вот какая ерунда.
Делаю, так:
1 случай
Код

procedure MasterDataset1BeforeScroll(Dataset: TDataset);
begin
   DetailDataset.DisableControls;
end;
procedure MasterDataset1AfterScroll(Dataset: TDataset);
begin
   DetailDataset.EnableControls;
end;

- в мастер таблице как раз выводится то, что мелькает!!! При том тут вообще, если отскроллить 
ДБГрид до конца, ничего не мелькает, но колом встает DBGridEh2.
2 случай
Если так:
Код

procedure MasterDataset1BeforeScroll(Dataset: TDataset);
begin
   DetailDataset.DisableControls;
end;

и только - то в мастер таблице все как надо (ничего не мелькает), но при переходе в DBGridEh2, 
скроллирование в нём не работает (и вообще все колом)!!! 
Если в этом же случае при нажатии на кнопку, показывающую DBGridEh2, пишу: DetailDataset.EnableControls; - все та же ненормальная ситуация

Уже пробовал что-нибудь сделать с событием onEndScroll - безрезультатно

Но чувствую - истина где-то рядом - но где? 

Автор: vv3 15.5.2006, 17:13
А не пробовал вообще с другой стороны подойти - запихнуть  Memo1.Lines.Add()  в событие DbgridEh.OnEnter?
smile 

Автор: santilaas 16.5.2006, 11:03
Да, как я я и думал всё было ещё проще:
у меня, как и говорил 2 DBGridEh-а (на форме кнопку нажимаешь - открывается один Grid, 
при этом у другого Grid-а Visible = False, другую кнопку нажимаешь - обратная ситуация).
Короче на первую кнопку я написал:
Код

   MasterDataset.EnableControls;
   DetailDataset.DisableControls;

 На другую:
Код

   DetailDataset.EnableControls;
   MasterDataset.DisableControls;

Короче получилось и без использования OnBeforeScroll и OnAfterScroll
vv3, Спасибо большое, за помощь.

У меня ещё маленький вопросик: DataSet-ы я активирую, когда открываю дочернюю форму,
а деактивировать их при её закрытии надо? или необязательно? Вообще, как правильно? 
Или на моё усмотрение? 

Автор: vv3 17.5.2006, 21:56
Цитата(santilaas @  16.5.2006,  11:03 Найти цитируемый пост)
Вообще, как правильно? 
Или на моё усмотрение?  

Именно, на твое усмотрение. У IBTransaction есть свойство taDefaultAction (что делать по умолчанию) и именно это она делает перед onDestroy... 
Если нужно особое поведение (я, например, при закрытии формы всегда опрашиваю состояние датасета и, если он редактировался, выдаю в TForm.onCloseQuery запрос на сохранение/отмену), то транзакцию можно откоммитить/отроллбэчить... Post/Cancel делать необязательно. 

Автор: santilaas 20.5.2006, 17:30
Понял.
vv3, ещё раз спасибо за помощь smile  

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)