![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
обработка данных КлиентДатасета в потоке [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]
> можно ли вообще так работать с потоками/данными?
Нельзя.
> в чем может быть ошибка?
В том что грид связан с дейтасетом через дейтасурс и при этом работает в основном потоке.
А какой вообще смысл выносить работу с дейтасетом в доп.поток, если основной поток только тем и занят, что следит за телодвижениями доп.потока и визуализирует их в гриде ?
С тем же успехом все это можно сделять прямо в основном потоке ..