Форум: "Основная";
Текущий архив: 2003.10.09;
Скачать: [xml.tar.bz2];
ВнизСоздание и отображение формы в отдельном потоке Найти похожие ветки
← →
bmasik (2003-09-25 11:04) [0]Господа, подскажите плизз,
Программа выполняет крупный запрос и соответственно отрисовка подвисает.
Хотелось бы в это время отобразить ну что то типа Прогресса.
Но при создании формы в потоке она все равно похоже цепляется к основному потоку приложения и ничего не отображает.
Create(nil) то же ничего не дает.
← →
panov (2003-09-25 11:05) [1]Код выложи.
← →
bmasik (2003-09-25 11:09) [2]
constructor TIdleFormThread.Create;
begin
inherited Create(False);
fmIdle:=TIdleForm.Create(nil);
Resume;
end;
destructor TIdleFormThread.Destroy;
begin
fmIdle.free;
inherited;
end;
procedure TIdleFormThread.Execute;
var
T:TDateTime;
begin
fmIdle.Show;
fmIdle.Refresh;
Screen.Cursor:=crHourGlass;
Randomize;
T:=Now;
while not Terminated do
begin
sleep(100);
fmIdle.ProgressBar.StepIt;
if fmIdle.ProgressBar.Position=100 then
fmIdle.ProgressBar.Position:=fmIdle.ProgressBar.Position-Random(100);
fmIdle.lTime.Caption:=TimeToStr(Now-T);
fmIdle.Refresh;
end;
end;
← →
dataMaster (2003-09-25 11:21) [3]Может попытатся вставить Application.ProcessMessages в тело цикла?
while not Terminated do
begin
Application.ProcessMessages
sleep(100);
fmIdle.ProgressBar.StepIt;
if fmIdle.ProgressBar.Position=100 then
fmIdle.ProgressBar.Position:=fmIdle.ProgressBar.Position-Random(100);
fmIdle.lTime.Caption:=TimeToStr(Now-T);
fmIdle.Refresh;
end;
← →
panov (2003-09-25 11:22) [4]Самое первое:
constructor TIdleFormThread.Create;
begin
inherited Create(True);
fmIdle:=TIdleForm.Create(nil);
Resume;
end;
Выложу работающий пример с пример с TGauge...
Для твоей задачи формочку с TProgressBar можно спокойно создать в основном потоке и обновлять периодически. Основной поток из-за этого не зависнет.
← →
panov (2003-09-25 11:23) [5]>dataMaster © (25.09.03 11:21) [3]
Может попытатся вставить Application.ProcessMessages в тело цикла?
Нет смысла в отдельном потоке.
← →
Bmasik (2003-09-25 11:25) [6]к сожалению бестолку, т.к. Application подвисает \причем наглухо\ до окончания выполнения операции.
← →
Verg (2003-09-25 11:27) [7]
> constructor TIdleFormThread.Create;
> begin
> fmIdle:=TIdleForm.Create(А чеж, сюда можно и Application);
> // Resume;
> inherited Create(False);
/// А то и до Access Violetion не далеко - чудесные эффекты ингда получаются иногда. Вчера вроде обсуждали подобное про Athlon-ы и "вдруг" неработающее приложение
> end;
>
> destructor TIdleFormThread.Destroy;
> begin
> fmIdle.free;
> inherited;
> end;
>
> procedure TIdleFormThread.Execute;
> var
> T:TDateTime;
> begin
> fmIdle.Show;
> fmIdle.Refresh;
> Screen.Cursor:=crHourGlass;
> Randomize;
> T:=Now;
> while not Terminated do
> begin
> sleep(100);
/// от сих .....
> fmIdle.ProgressBar.StepIt;
> if fmIdle.ProgressBar.Position=100 then
> fmIdle.ProgressBar.Position:=fmIdle.ProgressBar.Position-Random(100);
> fmIdle.lTime.Caption:=TimeToStr(Now-T);
> fmIdle.Refresh;
//... и до сих надо делать через Synchronize
> end;
> end;
← →
Verg (2003-09-25 11:38) [8]
> к сожалению бестолку, т.к. Application подвисает \причем
> наглухо\ до окончания выполнения операции.
Ах так вот оно что!
Запрос-то где выполняется ? В основном потоке?
Тогда с вами все ясно.
Вот запрос-то и надо помещать в отдельный поток.
См. пример
C:\Program Files\Borland\Delphi6\Demos\Db\BkQuery\
← →
bmasik (2003-09-25 11:43) [9]Да это и ежу понятно, но просто таких мест в системе программ довольно таки много, и не очень то тянет все их переписывать для того что бы нормально все отображалось.
:(
← →
Verg (2003-09-25 12:03) [10]Тогда не знаю.
Попробуйте создать это отдельное окошко средствами WinApi из контекста вашего потока и устроить там свой цикл PeekMessage -Translatemessage-dispatchmessage.
Не уверен, правда. Сам так никогда не делал....
Спроси еще у Игоря Шевченко.
← →
Erik (2003-09-25 12:29) [11]Помоему нечетко сформулирован вопрос, что надо перевести отрисовку в отдельный тред? Ели так то поместить в нутерь треда
repeat
Status := WaitForSingleObject(PI.hProcess, 30); //INFINITE
while PeekMessage(Msg, 0, 0, 0, pm_Remove) do begin
if Msg.Message = wm_Quit then Halt(Msg.WParam);
TranslateMessage(Msg);
DispatchMessage(Msg);
end;
until Status <> WAIT_TIMEOUT;
А что ожидать решиш сам, можно и MultiObject
← →
Polevi (2003-09-25 12:37) [12]>Erik (25.09.03 12:29) [11]
MsgWaitForMultipleObjects
а вообще отрисовкой должен заниматься основной поток, дополнительный должен лишь сообщать ему что данные изменились и их надо отобразить
← →
jack128 (2003-09-25 12:57) [13]Если ты создал окно к кострукторе потока, то оно(окно) пренадлежит ОСНОВНОМУ потоку, сообщения этому окну посылаются в очередь основного потока. Если нужно окно в доп потоке, то создавай его в TThread.Execute
А вообще
> а вообще отрисовкой должен заниматься основной поток, дополнительный
> должен лишь сообщать ему что данные изменились и их надо
> отобразить
← →
Erik (2003-09-25 13:05) [14]Как я понял у человека куча кода разбросаного бог знает где и надо както без большой переделки показывать прогрес. Это конечно изврат, но вопрос был задан именно так.
P.S.
Polevi ты думаеш я незню как API пишутся?
← →
Юрий Зотов (2003-09-25 13:05) [15]Брошу-ка и я свои 5 копеек. :о)
Итак:
"Программа выполняет крупный запрос и соответственно отрисовка подвисает"
Важный момент - отрисовка ЧЕГО подвисает?
Если речь идет об отрисовке просто какой-то формы (или форм) то достаточно вынести запрос в отдельный поток и все будет нормально.
А если речь идет об отрисовке прогрессбара то вопрос - а КАК Вы собираетесь обновлять этот прогрессбар?
Вообще говоря, схема тут совершенно стандартная и простая - запрос выполняется в дополнительном потоке, а прогрессбар живет в основном и в нужные моменты дополнительный поток сообщает главному (например, через PostMessage), что нужно обновить прогрессбар (и заодно передает нужную для этого обновления информацию). Получив сообщение и нужную информацию, основной поток делает обновление.
Так что проблема не в этом, а в том КАК и ОТКУДА дополнительный поток будет брать информацию о проценте выполнения запроса, например? От сервера? Тогда как? Еще откуда-то? Тогда откуда?
Значит, при выполнении запроса должна существовать какая-то обратная связь типа уведомлений "выполнено столько-то процентов". Создание такой связи - вот это и есть проблема, а вовсе не какая-то там перерисовка.
← →
panov (2003-09-25 13:07) [16]>jack128 © (25.09.03 12:57) [13]
Если ты создал окно к кострукторе потока, то оно(окно) пренадлежит ОСНОВНОМУ потоку, сообщения этому окну посылаются в очередь основного потока. Если нужно окно в доп потоке, то создавай его в TThread.Execute
Бесполезно.
Даже если форма(любой объект VCL, который приримает сообщения) будет создана в Execute, поток сообщений в приложении все равно один и, как только появится отрисовка объекта VCL в доп. потоке, основной поток сразу же застопорится.
← →
jack128 (2003-09-25 13:14) [17]
> Даже если форма(любой объект VCL, который приримает сообщения)
> будет создана в Execute, поток сообщений в приложении все
> равно один и, как только появится отрисовка объекта VCL
> в доп. потоке, основной поток сразу же застопорится.
Непонял..Если форма создана в доп потоке, по она пренадлежит этому доп потоку. Как собщение, посланое этой форме может очутиться в очереди основного потока??
← →
jack128 (2003-09-25 13:17) [18]Или у меня пробелы в базовых знаниях?
Я всегда считал, что окна "пренадлежат" тому потоку в контексте кототрого они были созданы. Сообщения посланные этим окнам(через PostMessage)поподают в очередь этого потока- владельца. Так??
← →
bmasik (2003-09-25 13:20) [19]Господа, Вы абсолютно правы, в данной ситуации лучше уж использовать какой нибудь внешний DLL для показа формы Прогресса, но "исть то оно исть, да ктож его дасьть"
jack128
А поток сообщений действительно один
← →
Юрий Зотов (2003-09-25 13:24) [20]> jack128 © (25.09.03 13:17) [18]
> Сообщения посланные этим окнам(через PostMessage)поподают в
> очередь этого потока- владельца. Так??
Так, но:
1. Сама очередь сообщений для потока будет создана системой лишь после того, как в этом потоке будет вызвана какая-либо из фунций User32.
2. Сам поток должен иметь цикл выборки сообшений из своей очереди и соответствующие оконные функции.
← →
Polevi (2003-09-25 13:30) [21]>Erik (25.09.03 13:05) [14]
API пишутся - Win32 API, ты принимал участие в его написании ? респект
а пример твой корявый
← →
jack128 (2003-09-25 14:07) [22]
> 1. Сама очередь сообщений для потока будет создана системой
> лишь после того, как в этом потоке будет вызвана какая-либо
> из фунций User32.
Так как CreateWindow(Ex) находятся как раз в user32.dll то создание окна в потоке автоматом приводит к созданию очереди.
> 2. Сам поток должен иметь цикл выборки сообшений из своей
> очереди и соответствующие оконные функции.
Я и не говорил обратного ;-)
← →
Erik (2003-09-25 14:42) [23]Пример как пример, я его из готового проекта выдрал и все прекрасно работало! Ты же незнаеш, что у меня за задача была. Это единственый пример здесь, к томуже провереный.
" в данной ситуации лучше уж использовать какой нибудь внешний DLL" а зачем?
← →
Polevi (2003-09-25 15:02) [24]про DLL это ты кому ?
а в примере твоем смущает тот факт что попток периодически просыпается чтобы проверить факт наличия сообщений в очереди
while not Terminated do
case MsgWaitForMultipleObjects(1, Event, False, INFINITE,QS_ALLEVENTS) of
WAIT_OBJECT_0:
Terminate;
WAIT_OBJECT_0 + 1:
while PeekMessage(msg, 0, 0, 0, PM_REMOVE) do DispatchMessage(msg);
end
← →
Erik (2003-09-25 15:10) [25]Так он у меня вегда спит и ничего неделает. Может и пороботать :)
А насчет MsgWaitForMultipleObjects я неуверен, что будет работать. Ведь сообщения приходять не треду а главному потоку.
← →
Verg (2003-09-25 15:20) [26]Нет, все понятно. Мне до конца не ясен вопрос:
Если я создам форму (TForm) в контексте неглавного потока и создам в нем же известный цикл выборки-обработки сообщений, то не будет никаких конфликтов с VCL? Все будет нормально работать?
Или это окно надо создавать "врукопашную" через WinApi и только так?
← →
Verg (2003-09-25 15:26) [27]Или за счет GlobalNameSpace полностью обеспечена потоконезависимость?
← →
Polevi (2003-09-25 15:27) [28]>Verg © (25.09.03 15:20) [26]
забудь, см
>а вообще отрисовкой должен заниматься основной поток, >дополнительный должен лишь сообщать ему что данные изменились и >их надо отобразить
>Erik (25.09.03 15:10) [25]
все будет ok, будь уверен :)
сообщения будут приходить в очередь сообщений того потока, в контексте которого окно было создано
← →
Verg (2003-09-25 16:00) [29]
> Polevi © (25.09.03 15:27) [28]
> забудь, см
> >а вообще отрисовкой должен заниматься основной поток, >дополнительный
> должен лишь сообщать ему что данные изменились и >их надо
> отобразить
Знаю, точнее думаю так же.
Но я спросил не об этом.
← →
ki11er (2003-09-25 16:38) [30]мда... |-O
← →
Verg (2003-09-25 17:06) [31]
> ki11er (25.09.03 16:38) [30]
А?
← →
Polevi (2003-09-25 19:08) [32]
type
TT=class(TThread)
private
FStopEvent:THandle;
FWaitTime:DWORD;
protected
procedure Execute;override;
procedure Stop;
end;
implementation
var
Z:integer;
function WndProc(wnd:HWND; msg:UINT; w:UINT; l:UINT):UINT;stdcall;
var
dc:HDC;
cr:TRect;
ps:PAINTSTRUCT;
str:string;
begin
case msg of
WM_PAINT:
begin
BeginPaint(wnd,ps);
GetClientRect(wnd,cr);
str:=IntToStr(Z);
DrawText(ps.hdc,PChar(str),Length(str),cr,DT_CENTER or DT_VCENTER or DT_SINGLELINE);
EndPaint(wnd,ps);
end
else
Result:=DefWindowProc(wnd,msg,w,l);
end;
end;
procedure TT.Stop;
begin
SetEvent(FStopEvent);
WaitFor;
end;
procedure TT.Execute;
var
msg:TMsg;
wnd:HWND;
wc:WNDCLASS;
lastTick:DWORD;
procedure OnIdle;
begin
if GetTickCount-LastTick>FWaitTime then
begin
LastTick:=GetTickCount;
InterlockedIncrement(Z);
InvalidateRect(wnd,nil,true);
end;
end;
begin
wc.style:=0;
wc.cbClsExtra:=0;
wc.cbWndExtra:=0;
wc.hInstance:=hInstance;
wc.hIcon:=0;
wc.hCursor:=0;
wc.hbrBackground:=GetStockObject(LTGRAY_BRUSH);
wc.lpszMenuName:=nil;
wc.lpszClassName:="TESTCLS";
wc.lpfnWndProc:=@WndProc;
Windows.RegisterClass(wc);
wnd:=CreateWindow("TESTCLS","Hello world",WS_CAPTION,CW_USEDEFAULT,CW_USEDEFAULT,200,80,HWND_DESKTOP,0,hInstance,nil);
ShowWindow(wnd,SW_NORMAL);
UpdateWindow(wnd);
FStopEvent:=CreateEvent(nil,false,false,nil);
FWaitTime:=100;
lastTick:=GetTickCount;
while not Terminated do
begin
OnIdle;
case MsgWaitForMultipleObjects(1, FStopEvent, False, FWaitTime, QS_ALLEVENTS) of
WAIT_OBJECT_0:Terminate;
WAIT_OBJECT_0+1:
while PeekMessage(msg, 0, 0, 0, PM_REMOVE) do
begin
TranslateMessage(msg);
DispatchMessage(msg);
end;
end;
end;
DestroyWindow(wnd);
CloseHandle(FStopEvent);
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
with TT.Create(true) do
begin
FreeOnTerminate:=true;
Resume;
end;
end;
← →
Verg (2003-09-25 19:20) [33]Ну вот видишь, bmasik, не все уж так и безнадежно :))
← →
nikkie (2003-09-27 12:09) [34]>[17] jack128 © (25.09.03 13:14)
>Непонял..Если форма создана в доп потоке, по она пренадлежит этому доп потоку. Как собщение, посланое этой форме может очутиться в очереди основного потока??
>[18] jack128 © (25.09.03 13:17)
>Или у меня пробелы в базовых знаниях?
>Я всегда считал, что окна "пренадлежат" тому потоку в контексте кототрого они были созданы. Сообщения посланные этим окнам(через PostMessage)поподают в очередь этого потока- владельца. Так??
разницу видишь? про окна ты все правильно говоришь, но VCL однопоточна - вот про что речь. попробуй, получится ли у тебя создать ФОРМУ в доп.потоке.
Страницы: 1 вся ветка
Форум: "Основная";
Текущий архив: 2003.10.09;
Скачать: [xml.tar.bz2];
Память: 0.54 MB
Время: 0.01 c