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

Вниз

Создание и отображение формы в отдельном потоке   Найти похожие ветки 

 
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;
Скачать: CL | DM;

Наверх




Память: 0.57 MB
Время: 0.018 c
8-27620
adam
2003-06-11 07:07
2003.10.09
mp3.... Как???


14-27730
Gimer
2003-09-19 13:48
2003.10.09
Прокся


4-27771
likeanangel
2003-08-04 12:39
2003.10.09
Использование графического пера


1-27607
Dionis
2003-09-28 17:33
2003.10.09
Как узнать месторасположение и размеры чужого окна?


1-27519
k_len
2003-09-26 11:03
2003.10.09
Форма