Чтение онлайн

на главную - закладки

Жанры

О чём не пишут в книгах по Delphi

Григорьев Антон Борисович

Шрифт:

 // риск ошибки ввода в тех случаях, когда требуется целое

 // неотрицательное число.

 SetWindowLong(EditNumber.Handle, GWL_STYLE, GetWindowLong(EditNumber.Handle, GWL_STYLE) or ES_NUMBER);

end;

procedure TForm1.BtnBroadcastClick(Sender: TObject);

var

 Num: Integer;

 Recipients: DWORD;

begin

 try

Num := StrToInt(EditNumber.Text);

// Для широковещательной рассылки сообщения служит

// функция BroadcastSystemMessage.
В литературе обычно

// советуют использовать более простую функцию

// PostMessage, указывая в качестве адресата

// HWND_BROADCAST. Однако PostMessage рассылает

// сообщения только окнам верхнего уровня, не имеющим

// владельца (в терминах системы). Но главная форма

// приложения имеет владельца - это невидимое окно

// приложения, реализуемое объектом TApplication.

// Поэтому такое широковещательное сообщение главная

// форма приложения не получит — его получит только

// невидимое окно приложения (это сообщение можно

// будет перехватить, назначив обработчик

// Application.OnMessage - вручную или с помощью

// компонента TApplicationEvents). Чтобы главная форма

// тоже попала в список окон, получающих

// широковещательное сообщение, используется функция

// BroadcastSystemMessage.

Recipients := BSM_APPLICATIONS;

BroadcastSystemMessage(BSF_POSTMESSAGE, @Recipients, FSendNumberMessage, Num, 0);

 except

on EConvertError do

begin

Application.MessageBox(

'Введенное значение не является числом', 'Ошибка',

MB_OK or MB_ICONSTOP);

end;

 end;

end;

procedure TForm1.WndProc(var Msg: TMessage);

begin

 if Msg.Msg = FSendNumberMessage then

LabelNumber.Caption := IntToStr(Msg.WParam)

 else inherited;

end;

end.

Как уже отмечалось ранее, для обработки глобального сообщения нельзя использовать методы с директивой

message
, т.к. номер сообщения на этапе компиляции еще не известен. Здесь для обработки глобального сообщения мы перекрываем метод
WndProc
. Соответственно, все оконные сообщения, в том числе и те, которые окно получает при создании, будет обрабатывать перекрытый метод
WndProc
. Это значит, что поле
FSendNumberMessage
, которое задействовано в этом методе, должно быть правильно инициализировано раньше, чем окно получит первое сообщение. Поэтому вызов функции
RegisterWindowMessage
выполнять, например, в обработчике события
OnCreate
формы уже поздно. Его необходимо выполнить в конструкторе формы, причем до того, как будет вызван унаследованный конструктор.

Примечание

Существует другой способ решения этой проблемы: метод

WndProc
должен проверять значение поля
FSendNumberMessage
, и, если оно равно нулю, сразу переходить к вызову унаследованного метода. В этом случае инициализировать
FSendNumberMessage
можно позже.

Нажатие на кнопку

BtnBroadcast
приводит к широковещательной отправке сообщения. Отправить широковещательное сообщение можно двумя способами: функцией
PostMessage
с адресатом
HWND_BROADCAST
вместо дескриптора окна и с помощью функции
BroadcastSystemMessage
. Первый вариант позволяет отправить сообщения только окнам верхнего уровня, не имеющим владельца в терминах системы. Таким окном в VCL-приложении является только невидимое окно приложения, создаваемое объектом
Application
. Главная форма имеет владельца в терминах системы — то самое невидимое окно приложения. Поэтому широковещательное сообщение, посланное с помощью
PostMessage
, главная форма не получит, это сообщение пришлось бы ловить с помощью события
Application.OnMessage
. Мы здесь применяем другой способ — отправляем сообщение с помощью функции
BroadcastSystemMessage
, которая позволяет указывать тип окон, которым мы хотим отправить сообщения. В частности, здесь мы выбираем тип
BSM_APPLICATION
, чтобы сообщение посылалось всем окнам верхнего уровня, в том числе и тем, которые имеют владельца. При таком способе отправки главная форма получит это широковещательное сообщение, поэтому его обработку можно реализовать в главной форме.

1.2.6. Пример ButtonDel

Программа ButtonDel демонстрирует, как можно удалить кнопку в обработчике нажатия этой кнопки. Очень распространенная ошибка — попытка написать код, один из примеров которого приведен в листинге 1.32.

Листинг 1.32. Неправильный вариант удаления кнопки в обработчике ее нажатия

procedure TForm1.Button1Click(Sender: TObject);

begin

 Button1.Free;

end;

Рассмотрим, что произойдет в случае выполнения этого кода. Когда пользователь нажимает на кнопку, форма получает сообщение

WM_COMMAND
. При обработке форма выясняет, что источником сообщения является объект
Button1
и передает этому объекту сообщение
CN_COMMAND
.
Button1
, получив его, вызывает метод
Click
, который проверяет, назначен ли обработчик
OnClick
, и, если назначен, вызывает его. Таким образом, после завершения
Button1Click
управление снова вернется в метод
Click
объекта
Button1
, из него — в метод
CNCommand
, из него — в
Dispatch
, оттуда — в
WndProc
, а оттуда — в
MainWndProc
. А из
MainWndProc
управление будет передано в оконную процедуру, сформированную компонентом с помощью
MakeObjectInstance
. В деструкторе
Button1
эта оконная процедура будет уже удалена. Таким образом, управление получат последовательно пять методов уже не существующего объекта и одна несуществующая процедура. Это может привести к самым разным неприятным эффектам, но, скорее всего, — к ошибке Access violation (обращение к памяти, которую программа не имеет права использовать). Поэтому приведенный в листинге 1.32 код будет неработоспособным. В классе
TCustomForm
для безопасного удаления формы существует метод
Release
, который откладывает уничтожение объекта до того момента, когда это будет безопасно, но остальные компоненты подобного метода не имеют.

Примечание

Метод

TCustomForm.Release
на поверку тоже оказывается не совсем безопасным — подробнее об этом написано в разд. 3.4.3.

Очевидно, что для безопасного удаления кнопки эту операцию следует отложить до того момента, когда все методы удаляемой кнопки уже закончат свою работу. Вставить требуемый код в обработчик

WM_COMMAND
формы достаточно сложно, поэтому мы будем использовать другой способ: пусть обработчик кнопки посылает форме сообщение, в обработчике которого она будет удалять кнопку. Здесь важно, что сообщение посылается, а не отправляется, т.е. ставится в очередь, из которой извлекается уже после того, как будет полностью обработано сообщение
WM_COMMAND
. В этом случае методы удаляемой кнопки не будут вызваны, и удаление пройдет без неприятных последствий.

Поделиться:
Популярные книги

Черный маг императора 3

Герда Александр
3. Черный маг императора
Фантастика:
попаданцы
аниме
5.00
рейтинг книги
Черный маг императора 3

Повелитель механического легиона. Том VIII

Лисицин Евгений
8. Повелитель механического легиона
Фантастика:
технофэнтези
аниме
фэнтези
5.00
рейтинг книги
Повелитель механического легиона. Том VIII

Пипец Котенку! 3

Майерс Александр
3. РОС: Пипец Котенку!
Фантастика:
юмористическое фэнтези
попаданцы
аниме
5.00
рейтинг книги
Пипец Котенку! 3

Разбуди меня

Рам Янка
7. Серьёзные мальчики в форме
Любовные романы:
современные любовные романы
остросюжетные любовные романы
5.00
рейтинг книги
Разбуди меня

Боги, пиво и дурак. Том 6

Горина Юлия Николаевна
6. Боги, пиво и дурак
Фантастика:
фэнтези
попаданцы
5.00
рейтинг книги
Боги, пиво и дурак. Том 6

Болотник 2

Панченко Андрей Алексеевич
2. Болотник
Фантастика:
попаданцы
альтернативная история
6.25
рейтинг книги
Болотник 2

Ты всё ещё моя

Тодорова Елена
4. Под запретом
Любовные романы:
современные любовные романы
7.00
рейтинг книги
Ты всё ещё моя

S-T-I-K-S. Пройти через туман

Елисеев Алексей Станиславович
Вселенная S-T-I-K-S
Фантастика:
боевая фантастика
7.00
рейтинг книги
S-T-I-K-S. Пройти через туман

Имя нам Легион. Том 4

Дорничев Дмитрий
4. Меж двух миров
Фантастика:
боевая фантастика
рпг
аниме
5.00
рейтинг книги
Имя нам Легион. Том 4

Сводный гад

Рам Янка
2. Самбисты
Любовные романы:
современные любовные романы
эро литература
5.00
рейтинг книги
Сводный гад

Я князь. Книга XVIII

Дрейк Сириус
18. Дорогой барон!
Фантастика:
юмористическое фэнтези
попаданцы
аниме
5.00
рейтинг книги
Я князь. Книга XVIII

Королевская Академия Магии. Неестественный Отбор

Самсонова Наталья
Любовные романы:
любовно-фантастические романы
8.22
рейтинг книги
Королевская Академия Магии. Неестественный Отбор

Последняя Арена 6

Греков Сергей
6. Последняя Арена
Фантастика:
рпг
постапокалипсис
5.00
рейтинг книги
Последняя Арена 6

Жребий некроманта. Надежда рода

Решетов Евгений Валерьевич
1. Жребий некроманта
Фантастика:
фэнтези
попаданцы
6.50
рейтинг книги
Жребий некроманта. Надежда рода