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

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

Жанры

О чём не пишут в книгах по 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
. В этом случае методы удаляемой кнопки не будут вызваны, и удаление пройдет без неприятных последствий.

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

Вкус ледяного поцелуя

Полякова Татьяна Викторовна
2. Ольга Рязанцева
Детективы:
криминальные детективы
9.08
рейтинг книги
Вкус ледяного поцелуя

Проблема майора Багирова

Майер Кристина
1. Спецназ
Любовные романы:
современные любовные романы
6.60
рейтинг книги
Проблема майора Багирова

Прометей: владыка моря

Рави Ивар
5. Прометей
Фантастика:
фэнтези
5.97
рейтинг книги
Прометей: владыка моря

Попаданка в академии драконов 4

Свадьбина Любовь
4. Попаданка в академии драконов
Любовные романы:
любовно-фантастические романы
7.47
рейтинг книги
Попаданка в академии драконов 4

(Не)зачёт, Дарья Сергеевна!

Рам Янка
8. Самбисты
Любовные романы:
современные любовные романы
5.00
рейтинг книги
(Не)зачёт, Дарья Сергеевна!

Запасная дочь

Зика Натаэль
Фантастика:
фэнтези
6.40
рейтинг книги
Запасная дочь

Дракон с подарком

Суббота Светлана
3. Королевская академия Драко
Любовные романы:
любовно-фантастические романы
6.62
рейтинг книги
Дракон с подарком

Отвергнутая невеста генерала драконов

Лунёва Мария
5. Генералы драконов
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Отвергнутая невеста генерала драконов

Случайная жена для лорда Дракона

Волконская Оксана
Фантастика:
юмористическая фантастика
попаданцы
5.00
рейтинг книги
Случайная жена для лорда Дракона

Тройняшки не по плану. Идеальный генофонд

Лесневская Вероника
Роковые подмены
Любовные романы:
современные любовные романы
6.80
рейтинг книги
Тройняшки не по плану. Идеальный генофонд

Идеальный мир для Лекаря 28

Сапфир Олег
28. Лекарь
Фантастика:
юмористическое фэнтези
аниме
фэнтези
5.00
рейтинг книги
Идеальный мир для Лекаря 28

Лейтенант космического флота

Борчанинов Геннадий
1. Звезды на погонах
Фантастика:
боевая фантастика
космическая фантастика
космоопера
рпг
фэнтези
фантастика: прочее
5.00
рейтинг книги
Лейтенант космического флота

Гарем на шагоходе. Том 5

Гремлинов Гриша
5. Волк и его волчицы
Фантастика:
боевая фантастика
фэнтези
5.00
рейтинг книги
Гарем на шагоходе. Том 5

Матабар III

Клеванский Кирилл Сергеевич
3. Матабар
Фантастика:
фэнтези
5.00
рейтинг книги
Матабар III