![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Этот таинственный MessageBox... [D7]
Bless © (2006-10-10 10:21:00)Сперва приведу тестовый пример.
Итак, создаем новое приложение с двумя формами. На form1 бросаем кнопку и пишем обработчик OnClick:
procedure TForm1.Button1Click(Sender: TObject);
begin
form2 := tform2.create(self);
end;
У form2 есть такие обработчики:
procedure TForm2.FormCreate(Sender: TObject);
begin
try
raise Exception.Create('my exception');
except
PostMessage(handle, WM_CLOSE,0,0);
Windows.MessageBox(0, '11', '22', mb_ok); //!!!!!!!!!!!!!!!!!!!!!!!
end;{try}
end;
procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction);
begin
action := caFree;
end;
Если поставить точку останова на выделенную строчку в TForm2.FormCreate и нажать f8, то меня заносит в обработчик TForm2.FormClose (!?!), после чего возвращает назад в TForm2.FormCreate (на последний end;). Почему это происходит?
Bless (2006-10-10 17:14:00) [1]Да, чуть не забыл.
Спасибо :)
Bless (2006-10-10 17:13:00) [2]
> han_malign © (10.10.06 12:02) [20]
> > Где об этом можно четко прочитать?
>
> Help->MessageBox->Flags: MB_APPLMODAL/MB_SYSTEMMODAL/MB_TASKMODAL
Что-то я здесь не нашел информации о том, какие сообщения обрабатываются внутри MessageBox.
> default © (10.10.06 12:31) [22]
> у тебя MessageBox вызывается немодально, поэтому ведётся
> обработка сообщений для всех окон и потому WM_CLOSE главного
> окна и обрабатывается
Даже если я вызову его немодально, WM_CLOSE все-равно обработается.
Видимо, в [11] я угадал правильно (точнее не угадал, а переспросил сказанное в [6]). Внутри MessageBox, похоже, действительно организован свой собственный цикл выборки сообщений, который и вызвал обработчик WM_CLOSE.
default (2006-10-10 12:49:00) [3]
> "пропускаются" циклом
пропускаются на обработку всмысле:)всмысле обрабатываются:)
default (2006-10-10 12:44:00) [4]
> отбирая в нём сообщения относящиеся только к созданному
> окну - это получится некое подобие модального вызова MessageBox
это лишь некое подобие
на самом деле модальный показ MessageBox блокирует не все сообщения для других окон
в чём легко убедиться, например, вызвав модально MessageBox на главном окне, потом открыть другую программу и снова исходную программу - и увидим, что главное окно перерисовалось - значит сообщения по отрисовке главного окна "пропускаются" циклом выборки сообщений генерируемым модальным вызовом MessageBox
а вот сообщения по закрытию окна в модальном вызове MessageBox не пропускаются
default (2006-10-10 12:31:00) [5]Bless © (10.10.06 12:13) [21]
представь, что вместо вызова MessageBox ты создаёшь окно для диалога с пользователем(через CreateWindow(Ex)) и запускаешь цикл выборки сообщений отбирая в нём сообщения относящиеся только к созданному окну - это получится некое подобие модального вызова MessageBox
а вот если ты принимаешь на обработку сообщения относящиеся ко всем окнам, то тогда это будет некое подобие немодального вызова MessageBox
у тебя MessageBox вызывается немодально, поэтому ведётся обработка сообщений для всех окон и потому WM_CLOSE главного окна и обрабатывается
Bless (2006-10-10 12:13:00) [6]
> Elen © (10.10.06 11:35) [17]
> Чего б не поставить PostMessage или Form2.close после всех
> нужных действий в Эксцепте?
В данном примере это можно сделать. Но к сути вопроса это отношения не имеет, а пример создан лишь для иллюстрации вопроса.
han_malign (2006-10-10 12:02:00) [7]
> Где об этом можно четко прочитать?
Help->MessageBox->Flags: MB_APPLMODAL/MB_SYSTEMMODAL/MB_TASKMODAL
модальные окна не блокируют(по умолчанию) очередь сообщений для других окон,
тут кто-то уже ставил MB на таймер и был (не)приятно удивлен...
Application.ProcessMessages
GetMessage(MSG, 0,...)
DispatchMessage
<MB.ProcessMessages>
GetMessage((MSG, зависит от флагов,...)
DispatchMessage
loop
loop
Плохиш (2006-10-10 11:44:00) [8]
> Так внутренний цикл MessageBox-а обрабатывает только сообщения,
> относящиеся к окну MessageBox-а или все-таки все сообщения?
MessageBox выполняется в основном потоке программы, а сообщения обрабатываются по потокам, а не по окнам.
Bless (2006-10-10 11:40:00) [9]
> Плохиш © (10.10.06 11:34) [16]
Т.е. я в [11] все верно написал?
Но меня как-то смущает:
> Игорь Шевченко © (10.10.06 10:52) [6]
> Bless © (10.10.06 10:46) [3]
> > Не совсем понимаю, что такое модальный message loop
> Выборка из очереди потока сообщений, относящихся только
> к определенному окну. Поток-то один, в недрах MessageBox
> крутится цикл выборки сообщений, который больше никому не
> отдает управления.
Так внутренний цикл MessageBox-а обрабатывает только сообщения, относящиеся к окну MessageBox-а или все-таки все сообщения? Где об этом можно четко прочитать?
Elen (2006-10-10 11:35:00) [10]
> Bless
Чего б не поставить PostMessage или Form2.close после всех нужных действий в Эксцепте?
Плохиш (2006-10-10 11:34:00) [11]
> Bless © (10.10.06 11:22) [11]
Объясняю на пальцах. Вызвав MessageBox, который ждёт, как, надеюсь, известно, реакции пользователя, ты передал управление из своей программы системе, а та в свою очередь включила обработку сообщений, потому что другим способом реакцию пользователя как-то узнать труднова-то. Соответственно были обработаны все сообщения пришедшие приложению. Тот же самый эффект ты получишь просто вызвав Application.ProcessMessages.
han_malign (2006-10-10 11:33:00) [12]MB_TASKMODAL
Bless (2006-10-10 11:32:00) [13]
> Замени MessageBox на любой другой оператор и будет практически
> та же реакция
Заменил наform2 := nil;. Реакция другая. Как и следовало ожидать, процедура TForm2.FormCreate отработала до конца и лишь затем был вызван TForm2.FormClose.
Bless (2006-10-10 11:28:00) [14]
> Elen © (10.10.06 10:59) [9]
> Поправочка - "вызываеш" надо читать "помешаеш в очередь
> сообщений"
Вот именно. Не вызываю, а помещаю в очередь, в расчете на то, что оно будет обработано не раньше, чем произойдет очередная выборка очередного сообщения из очереди сообщений. То есть всяко после TForm2.FormCreate, а не посредине него.
Elen (2006-10-10 11:25:00) [15]
> Bless
Нет когда ты возвал PostMessage. Ты поставил WM_Close в очередь событий. Просто перед ним были tit сообщения, ожидающие своей обработки. А когда дело дошло до WM_Close то пошло в close. Замени MessageBox на любой другой оператор и будет практически та же реакция Имхо
Bless (2006-10-10 11:22:00) [16]Или Вы хотите сказать, что обработчик сообщения WM_CLOSE для окна был вызван изнутри цикла MessageBox-а?
Bless (2006-10-10 11:18:00) [17]> Игорь Шевченко © (10.10.06 10:53) [8]
> Цикл выборки сообщений вызвал оконную процедуру формы для
> обработки синхронного сообщения, например.
Не понял. Где я ошибаюсь?
Вся программа по сути - это цикл обработки сообщений. В данный момент я как раз обрабатываю одно из них, которое завело меня в конечном итоге вprocedure TForm2.FormCreate. Когда я закончу, то попаду назад в цикл, который выберет следующее сообщение (которое вполне может оказаться WM_CLOSE, которое я туда поместил строчкойPostMessage(handle, WM_CLOSE,0,0);) из очереди и обработает его.
На самом деле все происходит не совсем так?
Elen (2006-10-10 10:59:00) [18]Поправочка - "вызываеш" надо читать "помешаеш в очередь сообщений"
Игорь Шевченко (2006-10-10 10:53:00) [19]Bless © (10.10.06 10:52) [5]
> Каким образом меня вдруг закинуло в цикл обработки сообщений,
> а потом вернуло обратно?
Цикл выборки сообщений вызвал оконную процедуру формы для обработки синхронного сообщения, например.
Elen (2006-10-10 10:53:00) [20]
> Bless
Ну ты ж вызываеш эту обработку через PostMessage(handle, WM_CLOSE,0,0)?
Верно ведь? Хендл то формовский