В проекте требуется выполнить формирование отчетов (запросы к БД длятся от 1 до 60 сек) с отображением формы ожидания и возможностью отмены в любой момент. При отмене долгого запроса (поскольку это не происходит мгновенно) форма ожидания должна отображаться с сообщением «отмена операции». SQL-сервер Firebird2.5Beta2, среда разработки Delphi 7.
Изучив статью http://mbo88.narod.ru/ToC.html плюс ветки, посвященные потокам, здесь на форуме, пошел таким путем:
1.Объявляю два класса
Код: Выделить всё
TSplashThread = class(TThread) //поток для отображения формы ожидания
private
tstbCancel: boolean; //признак «отмены»
procedure tstCheckStatusTerminate; //проверка статуса «отмена»
protected
procedure Execute; override;
end;
TExecThread = class(TThread) //поток для расчета и обновления формы ожидания
private
tetiProgress: integer; // прогресс бар
procedure tetSetProgress; // установка прогресс бара на форме ожидания
procedure tetSetSplashTerminate; //завершение расчета
protected
procedure Execute; override;
end;
Код: Выделить всё
if not assigned(formSplash) then
formSplash := TformSplash.Create(Application);
formSplash.Show;
SplashThread:=TSplashThread.Create(true);
SplashThread.FreeOnTerminate:=true;
SplashThread.tstbCancel := False;
SplashThread.Priority:=tpLower;
SplashThread.Resume;
Код: Выделить всё
delete from MON$ATTACHMENTS where MON$ATTACHMENT_ID=:I_CUR_CONNECT
Код метода Execute потока ожидания:
Код: Выделить всё
procedure TSplashThread.Execute;
var ExecThread: TExecThread;
begin
ExecThread:=TExecThread.Create(True);
ExecThread.FreeOnTerminate:=True;
ExecThread.Priority:=tpLower;
ExecThread.tetiProgress := 0;
ExecThread.Resume;
while (not tstbCancel) and (not Terminated) do //бесконечный цикл
begin
Synchronize(tstCheckStatusTerminate);
Application.ProcessMessages;
sleep(1);
end;
//отмена долгого запроса
dmDataDelConnects := TdmDataDelConnects.Create(Application);
dmDataDelConnects.fibDB.Connected := True;
dmDataDelConnects.fibqDelCC.Transaction.StartTransaction;
dmDataDelConnects.fibqDelCC.ParamByName('I_CUR_CONNECT').AsInteger := tstiCurConnect;
dmDataDelConnects.fibqDelCC.ExecQuery;
dmDataDelConnects.fibDB.Connected := False;
FreeAndNil(dmDataDelConnects);
ExecThread.Terminate; //останов потока расчета
end;
Код: Выделить всё
procedure TExecThread.tetSetSplashTerminate;
begin
if assigned(dmDataReps) then
begin
dmDataReps.fibDB.Connected := False;
FreeAndNil(dmDataReps);
end;
if Assigned(formSplash) then FreeAndNil(formSplash); //уничтожаю форму ожидания
end;
1.В связи с тем, что часто и где попало выпадают access violation, явно нарушен сам принцип работы с потоками. Ткните пожалуйста в самые проблемные места вышеописанного алгоритма.
2.При выполнении кода, отменяющего долгий запрос, сразу после ExecQuery (поток ожидания, операция отмены), почему-то с экрана пропадает форма ожидания. Закоментарил данный кусок кода, отменяющего запрос, запустил проект, отменил формирование расчета, после чего сразу же в Ибэксперте удалил строку в MON$ATTACHMENTS – эффект тот же, пропала форма ожидания. Чем вызвано такое поведение? Соответственно, если не удаляю, то форма отображается до завершения долгого запроса.
3.Проект запущен в Delphi. Выполняю вновь операцию отмены отчета, сразу после ExecQuery вылетает ошибка EOSError ‘System error. Code: 5. Отказано в доступе’. Это нормально? Проект после этого работает.
4.Наверняка кто-то уже решал подобную задачу. По возможности, поделитесь пожалуйста своими идеями, хотя бы в общих чертах описав подход и принцип реализации такого функционала.
5.Есть еще одна проблема – обновление по таймеру текущих данных, в данном конкретном проекте – значений электропотребления для выбранной расчетной группы. Проблема в том, что при выборе детализации «год по месяцам» запрос на обновление выполняется по времени до минуты. Возможно ли вынести это обновление в отдельный поток, предусмотрев досрочную отмену операции, и каким образом (принцип в общих чертах)?