Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

обработка данных КлиентДатасета в потоке [D7, XP]


Семен Кевларвестов ©   (2008-12-30 02:36:00) 

Доброй ночи!

Имеется нижеследующая ситуация: Есть грид (EhGrid), источников данных в нем служит ClientDataSet. Далее создается поток, в котором этот клиента пробегается от начала до конца и вызывается некая процедура. При это перед вызовом этой процедуры в поле со статусом клиентдатасета прописывается "Обработка началась", после - "Обработка завершена". Т.е., чтобы в гриде этот процесс обработки отображался и пользователь сильно не страдал.

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

Но имеется такая нехорошая штука: при обработки длинных наборов данных вылетают ошибки всякий раз разные, то не тот индекс в гриде, то ошибка при отрисовке скроллбара, то вообще АВ в модуле. Я так понимаю, что это глючит отрисовка грида. Т.к. если перед началом выполнения потока грид скрыть, а потом показать - все выполняется без жертв.

Вопрос: можно ли вообще так работать с потоками/данными? И в чем может быть ошибка? Может где-то чего то синхронизировать надо? Или как-то иначе грид обновлять?.


Loginov Dmitry   (2008-12-30 16:22:00) [1]

> Имеется нижеследующая ситуация: Есть грид (EhGrid), источников
> данных в нем служит ClientDataSet. Далее создается поток,
> в котором этот клиента пробегается от начала до конца и
> вызывается некая процедура. При это перед вызовом этой процедуры
> в поле со статусом клиентдатасета прописывается "Обработка
> началась", после - "Обработка завершена". Т.е., чтобы в
> гриде этот процесс обработки отображался и пользователь
> сильно не страдал.
>
> В тред все это засунуто, видимо, чтобы процесс можно было
> обрубить, т.к. процедуры достаточно длительныя.


для подобных задач как раз и разработан модуль progressviewer
( http://matrix.kladovka.net.ru/download.php?getfilename=uploads/other/progressviewer.zip)

В помощью него можно отказаться от потока, пользователь сможет видеть весь процесс обработки данных, и прервать его в любой момент. Код будет выглядеть примерно так:

DS.DisableControls;
try
 with TProgressViewer.Create('Обработка данных грида', True, True) do
 try
   DS.First;
   while not DS.Eof do
   begin
     CheckCancelByUser; // Если пользователь нажал "отмена", то генерируется исключение
     CurrentValue := (DS.RecNo / DS.RecordCount) * 100; // Выводим прогресс в процентах
     // ВЫПОЛНЯЕМ НЕОБХОДИМУЮ ОБРАБОТКУ
     DS.Next;
   end;
 finally
   Terminate; // завершаем поток визуализации
   DS.First;
 end;
finally
 DS.EnableControls;
end;


Игорь Шевченко   (2008-12-30 13:55:00) [2]


> Имеется нижеследующая ситуация: Есть грид (EhGrid), источников
> данных в нем служит ClientDataSet. Далее создается поток,
>  в котором этот клиента пробегается от начала до конца и
> вызывается некая процедура. При это перед вызовом этой процедуры
> в поле со статусом клиентдатасета прописывается "Обработка
> началась", после - "Обработка завершена". Т.е., чтобы в
> гриде этот процесс обработки отображался и пользователь
> сильно не страдал.


 TCheckThread = class(TThread)
 private
   FMember: TMemberModel;
   FBadReason: string;
   FErrorMessage: string;
   procedure AddMemberToBadList;
   procedure AfterFillCDS;
   procedure ShowError;
 public
   constructor Create;
   procedure Execute; override;
 end;

procedure TdmMember.AddMemberToBadMemberList(ObjectData: TMemberModel;
 const AReason: string);
begin
 with cdsBadMembers do
 begin
   Append;
   try
     FieldByName('MEMBER_ID').AsInteger := ObjectData.ID;
     FieldByName('LAST_NAME').AsString := ObjectData.LastName;
     FieldByName('FIRST_NAME').AsString := ObjectData.FirstName;
     FieldByName('SECOND_NAME').AsString := ObjectData.SecondName;
     FieldByName('SEX').AsString := ObjectData.Sex;
     FieldByName('OBJECT_DATA').AsInteger := Integer(ObjectData);
     FieldByName('REASON').AsString := AReason;
     Post;
   except
     Cancel;
   end;
 end;
end;

procedure TCheckThread.AddMemberToBadList;
begin
 dmMember.AddMemberToBadMemberList (FMember, FBadReason);
end;

procedure TCheckThread.AfterFillCDS;
begin
 with dmMember.cdsBadMembers do
 begin
   DisableControls;
   try
     IndexName := 'VIEWKEY';
     First;
   finally
     EnableControls;
   end;
 end;
end;

constructor TCheckThread.Create;
begin
 inherited Create (true);
 Priority := tpLower;
 FreeOnTerminate := true;
 Resume;
end;

procedure TCheckThread.Execute;
begin
 dmMember.CheckThreadRunning := true;
 with dmMember.qCheck do begin
   DisableControls;
   try
     if Active then
       First
     else
       Open;
     while not Eof and not Terminated do
     begin
       try
         dmMember.CheckedMembersCount := dmMember.CheckedMembersCount + 1;
         FMember := TMemberModel.Create;
         FMember.ID := FieldByName('MEMBER_ID').AsInteger;
         dmMember.LoadObject(FieldByName('MEMBER_ID').AsInteger, FMember);
         FBadReason := FMember.HasInconsistentData;
         if FieldByName('HASCARD').AsString = 'N' then
         begin
           if FBadReason <> '' then
             FBadReason := FBadReason + ',';
           FBadReason := FBadReason + g_NoCard;
         end;
         if FBadReason <> '' then
           Synchronize(AddMemberToBadList)
         else
           FMember.Free;
       except
         on E: Exception do begin
           FErrorMessage := E.Message;
           Synchronize(ShowError);         
         end;
       end;
       Next;
     end;
   finally
     First;
     EnableControls;
   end;
 end;
 Synchronize(AfterFillCDS); 
 dmMember.CheckThreadRunning := false;
end;

procedure TCheckThread.ShowError;
begin
 ShowMessage(FErrorMessage);
end;


Все прекрасно работает, данные в гриде ползут по мере поступления, можно заниматься другими делами пока грид не заполнится.
Единственное - подключение к базе данных для датасетов, работа с которыми выполняется в потоке, я всегда делаю отдельное.


qqq   (2008-12-30 10:49:00) [3]

временно отцепи датасорс от датасета
м.б. поможет просто disablecontrols


MsGuns   (2008-12-30 09:19:00) [4]

Запускать "пробежки" по визуализированному НД во вторичном потоке - штука крайне рискованная и требует блокировки ЛЮБЫХ перерисовок канвы (и не только). Поэтому если так уж надо "в потоке", то лучше создать клон (если датасет АДОшный) и по нему "бегать".


Сергей М.   (2008-12-30 08:33:00) [5]


> можно ли вообще так работать с потоками/данными?


Нельзя.


> в чем может быть ошибка?


В том что грид связан с дейтасетом через дейтасурс и при этом работает в основном потоке.

А какой вообще смысл выносить работу с дейтасетом в доп.поток, если основной поток только тем и занят, что следит за телодвижениями доп.потока и визуализирует их в гриде ?
С тем же успехом все это можно сделять прямо в основном потоке ..


Наверх

Титульная страница Поиск, карта сайта Написать письмо