Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Основная";
Текущий архив: 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
1-27478
Charly
2003-09-19 22:58
2003.10.09
Остановить выполнение нити


3-27398
Russko
2003-09-18 13:17
2003.10.09
Wise For Windows Installer


1-27577
sagchat
2003-09-29 14:06
2003.10.09
Как мне показывать случайную строку из memo или из файла


1-27472
pum5a
2003-09-26 22:07
2003.10.09
Как создать окно для контрола


1-27429
Viktor Kushnir
2003-09-28 14:13
2003.10.09
RGB наоборот.





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский