![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Отображение длительных процессов [WinXP]
BanderLog © (2006-02-13 10:45:00)Привет мастерам!
Необходимо в программе при выполнении длительной операции показывать окно с какой либо надписью, вроде "Идет обработка вышего запроса". При этом основное окно не должно быть доступно. К тому же необходимо иметь на этой форме кнопочку "Отмена" (опционально), для отмены операции.
Подскажите в какую сторону смотреть и как лучше подобное реализовать?
Игорь Шевченко (2006-02-17 20:54:00) [1]Defunct © (17.02.06 19:11) [26]
Тем, что иногда перенос дополнительных действий в другой поток ведет к неоправданным затратам. Например, для того, чтобы выполнить запрос к базе данных в отдельном потоке, часто необходимо создать новое подключение к ней.
Все зависит от задачи, как всегда.
> Просто в свете ограничений связанных с VCL впервые слышу
> о подобном способе реализации анимации.
MS вроде документирует этот способ. По таймеру показывается последовательность картинок при анимации.
Defunct (2006-02-17 19:11:00) [2]
> Игорь Шевченко © (16.02.06 16:09) [20]
> Defunct © (16.02.06 15:16) [19]
>
> Имелся в виду аналог стандартной анимации Windows, где действия
> (например, по копированию больших файлов) выполняются в
> основном потоке, а обновление изображения на заставке при
> копировании в проводнике - в дополнительном.
А чем такой способ лучше обратного (анимация в основном, действия в доп. потоке)?
Просто в свете ограничений связанных с VCL впервые слышу о подобном способе реализации анимации.
Игорь Шевченко (2006-02-17 15:55:00) [3]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.
Mikhail (2006-02-17 15:40:00) [4]
> Fay © (17.02.06 14:39) [23]
Для интереса попробовал. А это кусочек, возможно не очень вразумительный.
Fay (2006-02-17 14:39:00) [5]2 Mikhail (17.02.06 14:37) [22]
Что это было?
Mikhail (2006-02-17 14:37:00) [6]
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;
BanderLog (2006-02-17 12:59:00) [7]
> 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, где действия
> (например, по копированию больших файлов) выполняются в
> основном потоке, а обновление изображения на заставке при
> копировании в проводнике - в дополнительном.
Абсолютно верно. Хочется узнать о возможных путях реализации данного варианта.
Игорь Шевченко (2006-02-16 16:09:00) [8]Defunct © (16.02.06 15:16) [19]
Имелся в виду аналог стандартной анимации Windows, где действия (например, по копированию больших файлов) выполняются в основном потоке, а обновление изображения на заставке при копировании в проводнике - в дополнительном.
Defunct (2006-02-16 15:16:00) [9]Игорь Шевченко © (16.02.06 14:06) [16]
Имелось в виду наоборот?
Digitman (2006-02-16 14:28:00) [10]
> BanderLog (16.02.06 13:57) [15]
А теперь - внятно..
BanderLog (2006-02-16 14:14:00) [11]Подскажите как это сделать, пожалуйста.
Игорь Шевченко (2006-02-16 14:06:00) [12]Не надо в доп. потоке запрос выполнять, надо в доп. потоке форму для пользователя показывать
BanderLog (2006-02-16 13:57:00) [13]
> Digitman © (13.02.06 11:57) [13]
> Ну и покажи это средствами Form.ShowModal !
> В чем проблема-то ?
ShowModal заморозит основной процесс пока не юудет закрыто окно, чем мне это поможет?
Вопрос, внутри потока можно создать форму, которая будет работать в этом потоке и при его завершениии будет уничтожаться? Эта форма никак не должна взаимодействовать с главной. (допустим, нажал в главной программе кнопку - запустился поток, который создал форму с обычным лебел, который отображает текущее время, надоело это окно пользователю, выключил его)
Maverick (2006-02-13 12:13:00) [14]>Digitman © (13.02.06 11:57) [13]
согласен, каюсь, выдернул от куда то пример, толком его не просмотрев :)
я хотел просто показать человеку возможный подход..а в теле процедуры incedit можно отписать sql запрос...
Digitman (2006-02-13 11:57:00) [15]1. incedit д.б. объявлена так:
function incedit(Parameter: Pointer): Integer;
2. Обращения к визуальным vcl-контролам в контексте до.потока vcl-приложения недопустимы
> BanderLog (13.02.06 11:35) [12]
Ну и покажи это средствами Form.ShowModal !
В чем проблема-то ?
BanderLog (2006-02-13 11:35:00) [16]Достаточно показать пользователю сообщение и заблокировать основную форму, так как покуда не будут найдены необходимые данные пользователю и программа не нужна... показывать такое сообщение надо будет не только при выполнении запроса, но и при пакетной обработке файлов другим приложением которое запускается через CreateProcess и WaitForSingleObject, которую и нужно будет отменять.
Maverick (2006-02-13 11:30:00) [17]> Digitman © (13.02.06 11:27) [10]
>Выкинь этот пример в мусор.
>В нем - грубые ошибки.
поясни, плз...
(я сам тока учусь :) )
Digitman (2006-02-13 11:27:00) [18]
> Maverick © (13.02.06 11:23) [9]
> для примера, вот нашел...как по простому вызвать процедуру
> в доп.потоке
Выкинь этот пример в мусор.
В нем - грубые ошибки.
Maverick (2006-02-13 11:23:00) [19]для примера, вот нашел...как по простому вызвать процедуру в доп.потоке
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:12:00) [20]
> BanderLog (13.02.06 11:10) [6]
Запусти запрос на выполнение в доп.потоке.
А в основном потоке покажи юзеру какой-нть прогресс был или анимацию, создающие иллюзию "бурной деятельности" твоей программы