Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2006.03.19;
Скачать: CL | DM;

Вниз

Отображение длительных процессов   Найти похожие ветки 

 
BanderLog   (2006-02-13 10:45) [0]

Привет мастерам!
Необходимо в программе при выполнении длительной операции показывать окно с какой либо надписью, вроде "Идет обработка вышего запроса". При этом основное окно не должно быть доступно. К тому же необходимо иметь на этой форме кнопочку "Отмена" (опционально), для отмены операции.
Подскажите в какую сторону смотреть и как лучше подобное реализовать?


 
Marser ©   (2006-02-13 10:46) [1]

Application.ProcessMessages


 
BanderLog   (2006-02-13 10:51) [2]

И куда его писать? :)


 
ЮЮ ©   (2006-02-13 10:57) [3]

В тот цикл, который мещает нажать кнопкку "отмена" и перерисовывть форму. А в кнопке отмена надо сделать такие дейтствия, чтобы когда прожолжится выполнение цикла стало ясно, что следкет прервать цикл.


 
BanderLog   (2006-02-13 11:04) [4]

А если длительная операция это выполнение SQL запроса?


 
Digitman ©   (2006-02-13 11:06) [5]


> BanderLog   (13.02.06 11:04) [4]


СУБД какая ?


 
BanderLog   (2006-02-13 11:10) [6]

FireBird, но прерывать SQL запрос не надо :) Необходимо просто показать сообщение что он выполняется и основную форму закрыть для доступа.


 
ЮЮ ©   (2006-02-13 11:11) [7]

Тогда лучше оптимизировать запрос :)
Или выполнять его в отдельном Thread-е с убитием последнего.
Или выполнять в асинхронном режиме с убитием, наверное, компонента или вызовов надлежащего метода.


 
Digitman ©   (2006-02-13 11:12) [8]


> BanderLog   (13.02.06 11:10) [6]


Запусти запрос на выполнение в доп.потоке.
А в основном потоке покажи юзеру какой-нть прогресс был или анимацию, создающие иллюзию "бурной деятельности" твоей программы


 
Maverick ©   (2006-02-13 11:23) [9]

для примера, вот нашел...как по простому вызвать процедуру в доп.потоке

unit Unit1;

interface

uses
 Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
 StdCtrls;

procedure incedit1; stdcall;
procedure incedit2; stdcall;

type
 TForm1 = class(TForm)
   Button1: TButton;
   Edit1: TEdit;
   Edit2: TEdit;
   Button6: TButton;
   Button7: TButton;
   Button2: TButton;
   Button3: TButton;
   Button5: TButton;
   Button4: TButton;
   procedure Button1Click(Sender: TObject);
   procedure Button6Click(Sender: TObject);
   procedure Button7Click(Sender: TObject);
   procedure Button4Click(Sender: TObject);
   procedure Button5Click(Sender: TObject);
   procedure Button2Click(Sender: TObject);
   procedure Button3Click(Sender: TObject);
 private
   { Private declarations }
 public
   { Public declarations }
 end;

var
 Form1: TForm1;

implementation

var
 th1, th2: cardinal;
 h1, h2: integer;

procedure incedit1;
var
 i: integer;
begin
 i := 0;
 while true do
 begin
   form1.edit1.text := inttostr(i);
   i := i + 1;
 end;
end;

procedure incedit2;
var
 i: integer;
begin
 i := 0;
 while true do
 begin
   form1.edit2.text := inttostr(i);
   i := i + 1;
 end;
end;
{$R *.DFM}

procedure TForm1.Button1Click(Sender: TObject);
begin
 h1 := beginthread(nil, 1024, @incedit1, nil, 0, th1);
 h2 := beginthread(nil, 1024, @incedit2, nil, 0, th2);
end;

procedure TForm1.Button6Click(Sender: TObject);
begin
 terminatethread(h1, 0);
end;

procedure TForm1.Button7Click(Sender: TObject);
begin
 terminatethread(h2, 0);
end;

procedure TForm1.Button4Click(Sender: TObject);
begin
 resumethread(h1);
end;

procedure TForm1.Button5Click(Sender: TObject);
begin
 resumethread(h2);
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
 suspendthread(h1);
end;

procedure TForm1.Button3Click(Sender: TObject);
begin
 suspendthread(h2);
end;

end.


 
Digitman ©   (2006-02-13 11:27) [10]


> Maverick ©   (13.02.06 11:23) [9]
> для примера, вот нашел...как по простому вызвать процедуру
> в доп.потоке


Выкинь этот пример в мусор.
В нем - грубые ошибки.


 
Maverick ©   (2006-02-13 11:30) [11]

> Digitman ©   (13.02.06 11:27) [10]
>Выкинь этот пример в мусор.
>В нем - грубые ошибки.

поясни, плз...
(я сам тока учусь :)  )


 
BanderLog   (2006-02-13 11:35) [12]

Достаточно показать пользователю сообщение и заблокировать основную форму, так как покуда не будут найдены необходимые данные пользователю и программа не нужна... показывать такое сообщение надо будет не только при выполнении запроса, но и при пакетной обработке файлов другим приложением которое запускается через CreateProcess и WaitForSingleObject, которую и нужно будет отменять.


 
Digitman ©   (2006-02-13 11:57) [13]

1. incedit д.б. объявлена так:

function incedit(Parameter: Pointer): Integer;

2. Обращения к визуальным vcl-контролам в контексте до.потока vcl-приложения недопустимы


> BanderLog   (13.02.06 11:35) [12]


Ну и покажи это средствами Form.ShowModal !
В чем проблема-то ?


 
Maverick ©   (2006-02-13 12:13) [14]

>Digitman ©   (13.02.06 11:57) [13]

согласен, каюсь, выдернул от куда то пример, толком его не просмотрев :)
я хотел просто показать человеку возможный подход..а в теле процедуры incedit можно отписать sql запрос...


 
BanderLog   (2006-02-16 13:57) [15]


> Digitman ©   (13.02.06 11:57) [13]
> Ну и покажи это средствами Form.ShowModal !
> В чем проблема-то ?

ShowModal заморозит основной процесс пока не юудет закрыто окно, чем мне это поможет?

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


 
Игорь Шевченко ©   (2006-02-16 14:06) [16]

Не надо в доп. потоке запрос выполнять, надо в доп. потоке форму для пользователя показывать


 
BanderLog   (2006-02-16 14:14) [17]

Подскажите как это сделать, пожалуйста.


 
Digitman ©   (2006-02-16 14:28) [18]


> BanderLog   (16.02.06 13:57) [15]


А теперь -  внятно..


 
Defunct ©   (2006-02-16 15:16) [19]

Игорь Шевченко ©   (16.02.06 14:06) [16]

Имелось в виду наоборот?


 
Игорь Шевченко ©   (2006-02-16 16:09) [20]

Defunct ©   (16.02.06 15:16) [19]

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


 
BanderLog   (2006-02-17 12:59) [21]


> Digitman ©   (16.02.06 14:28) [18]
> А теперь -  внятно..


SplashForm.ShowModal;
SQL.Open;

Когда у меня начнется начнется открываться запрос?
Может Вас смутило слово "заморозит", то согласен, некорректная формулировка, но смысл ясен, код продожиться выполняться только после того как модальное окно будет закрыть. (или может я чего то не понимаю в данном случае)


> Игорь Шевченко ©   (16.02.06 16:09) [20]
> Defunct ©   (16.02.06 15:16) [19]
>
> Имелся в виду аналог стандартной анимации Windows, где действия
> (например, по копированию больших файлов) выполняются в
> основном потоке, а обновление изображения на заставке при
> копировании в проводнике - в дополнительном.


Абсолютно верно. Хочется узнать о возможных путях реализации данного варианта.


 
Mikhail   (2006-02-17 14:37) [22]


procedure TForm1.Button1Click(Sender: TObject);
var
 i: Integer;
begin
 T := TSQThread.Create;
 Sleep(1000);
 SQL.Open;
end;

...

procedure TSQThread.Execute;
begin
 TForm2.Create(nil).ShowModal;
end;


 
Fay ©   (2006-02-17 14:39) [23]

2 Mikhail   (17.02.06 14:37) [22]
Что это было?


 
Mikhail   (2006-02-17 15:40) [24]


> Fay ©   (17.02.06 14:39) [23]

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


 
Игорь Шевченко ©   (2006-02-17 15:55) [25]

BanderLog   (17.02.06 12:59) [21]


> Абсолютно верно. Хочется узнать о возможных путях реализации
> данного варианта.


Канва примерно такая (писано на скорую руки, возможны ошибки). Долгое действие имитировалось таймером.

unit main;

interface

uses
 Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
 ExtCtrls, StdCtrls, ProgressThread;

type
 TfMain = class(TForm)
   Button: TButton;
   Timer: TTimer;
   procedure ButtonClick(Sender: TObject);
   procedure TimerTimer(Sender: TObject);
 private
   FProgressThread: TProgressThread;
   procedure LongProcessStarted;
   procedure LongProcessCompleted;
 end;

var
 fMain: TfMain;

implementation

{$R *.DFM}

procedure TfMain.ButtonClick(Sender: TObject);
begin
 LongProcessStarted;
 Timer.Enabled := true;
end;

procedure TfMain.LongProcessCompleted;
begin
 FProgressThread.Terminate;
 FProgressThread.WaitFor;
 FProgressThread.Free;
end;

procedure TfMain.LongProcessStarted;
begin
 FProgressThread := TProgressThread.Create (Self);
end;

procedure TfMain.TimerTimer(Sender: TObject);
begin
 LongProcessCompleted;
end;

end.


unit ProgressThread;

interface

uses
 Windows, Forms, Classes;

type
 TProgressThread = class(TThread)
 private
   FParentWidth, FParentHeight: Integer;
   FWindow: HWND;
   FParentWindow: HWND;
   function InitProgressThread: Boolean;
 protected
   procedure Execute; override;
 public
   constructor Create (ParentForm: TForm);
   destructor Destroy; override;
 end;

implementation
uses
 SysUtils, Messages;

function ThreadWndProc (Wnd: HWND; Message: UINT; wParam: WPARAM;
 lParam: LPARAM): LRESULT; stdcall;
var
 ps: PAINTSTRUCT;
 rctext: TRect;
begin
 case Message of
 WM_TIMER:
   begin
     if wParam = 1000 then begin
       InvalidateRect (Wnd, nil, false);
       Result := 0;
     end else
       Result := DefWindowProc (Wnd, Message, wParam, lParam);
   end;
 WM_DESTROY:
   begin
     KillTimer(Wnd, 1000);
     PostQuitMessage(0);
     Result := 0;
   end;
 WM_PAINT:
   begin
     BeginPaint(Wnd, ps);
     SetTextColor(ps.hdc, 0);
     GetClientRect(Wnd, rctext);
     DrawText (ps.hdc, PChar(Format("running %d", [GetTickCount])), -1,
       rctext, DT_CENTER or DT_VCENTER);
     EndPaint(Wnd, ps);
     Result := 0;
   end;
 else
   Result := DefWindowProc (Wnd, Message, wParam, lParam);
 end;
end;

function TProgressThread.InitProgressThread: Boolean;
const
 Height = 100;
 Width = 200;
var
 wc: WNDCLASS;
begin
 FillChar (wc, SizeOf(wc), 0);
 wc.lpfnWndProc := @ThreadWndProc;
 wc.lpszClassName := "HSProgressWindowClass";
 wc.hInstance := HInstance;
 wc.hbrBackground := GetStockObject(WHITE_BRUSH);
 Result := Windows.RegisterClass(wc) <> 0;
 if not Result then
   Exit;
 FWindow := CreateWindowEx (0, "HSProgressWindowClass", "ProgressWindow",
   WS_CHILD or WS_VISIBLE or WS_BORDER, (FParentWidth - Width) div 2,
     (FParentHeight - Height) div 2, Width, Height, FParentWindow, 1,
     HInstance, Self);
 Result := IsWindow(FWindow);
 if not Result then
   Exit;
 SetTimer(FWindow, 1000, 500, nil);
 UpdateWindow(FWindow);
end;

{ TProgressThread }

constructor TProgressThread.Create(ParentForm: TForm);
begin
 FreeOnTerminate := false;
 FParentWidth := ParentForm.Width;
 FParentHeight := ParentForm.Height;
 FParentWindow := ParentForm.Handle;
 inherited Create (false);
end;

procedure TProgressThread.Execute;
var
 Msg: TMsg;
begin
 if not InitProgressThread then
   Exit;
 while GetMessage(Msg, FWindow, 0, 0) and not Terminated do begin
   TranslateMessage(Msg);
   DispatchMessage(Msg);
 end;
 if Terminated then
   DestroyWindow(FWindow);
end;

destructor TProgressThread.Destroy;
begin
 Windows.UnregisterClass("HSProgressWindowClass", HInstance);
 inherited;
end;

end.


 
Defunct ©   (2006-02-17 19:11) [26]


> Игорь Шевченко ©   (16.02.06 16:09) [20]
> Defunct ©   (16.02.06 15:16) [19]
>
> Имелся в виду аналог стандартной анимации Windows, где действия
> (например, по копированию больших файлов) выполняются в
> основном потоке, а обновление изображения на заставке при
> копировании в проводнике - в дополнительном.


А чем такой способ лучше обратного (анимация в основном, действия в доп. потоке)?
Просто в свете ограничений связанных с VCL впервые слышу о подобном способе реализации анимации.


 
Игорь Шевченко ©   (2006-02-17 20:54) [27]

Defunct ©   (17.02.06 19:11) [26]

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

Все зависит от задачи, как всегда.


> Просто в свете ограничений связанных с VCL впервые слышу
> о подобном способе реализации анимации.


MS вроде документирует этот способ. По таймеру показывается последовательность картинок при анимации.



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

Текущий архив: 2006.03.19;
Скачать: CL | DM;

Наверх




Память: 0.55 MB
Время: 0.03 c
11-1122376775
RA
2005-07-26 15:19
2006.03.19
Для чего это "Can not change font ..."?


15-1140978453
Volf_555
2006-02-26 21:27
2006.03.19
Какой посоветуете поставить форум в локальной сети?


2-1141304720
Мультик
2006-03-02 16:05
2006.03.19
Рисунки в БД ACCESS


15-1140775934
DSKalugin
2006-02-24 13:12
2006.03.19
Способы защиты exe/dll от модификации ресурсов


15-1140472832
GanibalLector
2006-02-21 01:00
2006.03.19
Снифер для GPRS сетей