Форум: "Основная";
Текущий архив: 2006.03.19;
Скачать: [xml.tar.bz2];
ВнизОтображение длительных процессов Найти похожие ветки
← →
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;
Скачать: [xml.tar.bz2];
Память: 0.53 MB
Время: 0.014 c