<<
>>

Создание и обработка сообщений и событий

Стандартная библиотека классов Delphi VCL предлагает разработчику достаточно большой набор сообщений и методов их разработки. Однако он имеет возможность добавить новое сообщение или переопределить методы обработки существующих сообщений.

При создании нового сообщения необходимо выполнить следующие действия:

1) описать тип сообщения;

2) объявить номер (или индекс) сообщения;

3) объявить метод обработки нового сообщения в классе, который должен его обрабатывать;

4) инициализировать (передать) сообщение.

Сообщения Delphi. В Delphi определено около 100 стандартных типов сообщений. В соответствии с правилами Windows сообщение состоит из нескольких полей. Первое поле обычно называется Msg. Оно должно содержать индекс сообщения — 16-разрядное целое положительное число (тип Cardinal). Далее следуют поля, содержащие передаваемые значения. Последние поля обычно используются для записи результата обработки сообщения. Они могут отсутствовать.

Например, основной тип сообщений, используемых в Delphi, определяется следующим образом:

Type TMessage=record Msg: Cardinal; case Integer of

0: (WParam:LongInt; LParam.Longlnt; Result:Longlnt);

1: (WParamLo.WordWParamHi:Word;

LParamLo.Word; LParamHi.Word;

ResultLo.Word; ResultHvWord); end; end;

Номер сообщения.

Номер (или индекс) сообщения используется для идентификации сообщения в системе: он определяет вид события, о котором система уведомляет приложение (нажатие клавиш, нажатие кнопок мыши и

Т.Д.).

При создании собственных сообщений следует учитывать, что номера с 0 до $399 зарезервированы за системой. Первый свободный номер обозначен константой WM USER=$400, относительно которой обычно и определяются номера пользовательских сообщений:

Const Mesl = WMJJSER;

Mes2 = WMJJSER+1;

Методы обработки сообщений.

Класс, объекты которого должны принимать и обрабатывать некоторые сообщения, должен включать специальные методы обработки этих сообщений. При разработке этих методов необходимо учитывать специальные правила, существующие в Delphi.

Метод обработки сообщения по умолчанию является динамическим, причем спецификаторы dinamic или override при его описании опускаются:

Procedure wiu(уаг Message:«ran сообщения>);

message inherited; end;

В том случае, если у объекта для некоторого сообщения не определен соответствующий обработчик, то, в соответствии с правилами подключения динамических методов проверяются таблицы динамических методов базовых классов. Если обработчик некоторого сообщения не определен и в базовых классах, то проводится вызов метода DefaultHandler класса TObject, который обеспечивает «обработку по умолчанию» для этих сообщений.

Генерация сообщения. Для передачи сообщений объектам Delphi могут использоваться несколько способов.

1. Для передачи сообщения оконному элементу управления через очередь сообщений с ожиданием завершения его обработки используется функция:

function SendMessage (hWnd: Integer, Mes:Cardinal;

WParam, LParam:LongInt):LongInt;

Она возвращает результат обработки сообщения. Параметр hWnd определяет номер, под которым окно - адресат сообщения - зарегистрировано

в Windows (дескриптор окна). Для каждого оконного элемента управления этот номер хранится в свойстве Handle, определенном в классе TWinControl.

2. Для передачи сообщения оконному элементу управления через очередь сообщений без ожидания завершения его обработки используется функция:

function PostMessage(hWnd:Integer,Mes:Cardinal;

WParam,Param: Longlnt): LongBool;

Список параметров функции совпадает со списком SendMessage, но в отличие от SendMessage PostMessage ставит сообщение в очередь сообщений и возвращает управление, не ожидая завершения обработки сообщения. Функция возвращает True, если сообщение поставлено в очередь, и False - в противном случае.

3. Для передачи сообщения элементу управления минуя очередь используется специальный метод этого элемента, определенный в классе TControl:

procedure Perform (Mes:Cardinal; WParam, LParam:Longlnt);

Данный метод передает сообщение элементу управления непосредственно, поэтому указывать дескриптор окна не надо, и список параметров содержит только параметры, относящиеся к самому сообщению.

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

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

Прежде всего, в интерфейсной части модуля Unit 1 определим тип нового сообщения и константу, определяющую его номер. Далее в классе TForml зарезервируем поле для хранения дескриптора второй формы и организуем пересылку сообщения в очередь по нажатию кнопки SendButton:

Рис. 5.20. Вид окон приложения «Передача/прием сообщений»

Unit Until;

Interface

Type MyMessage=Record

Msg.'Cardinal; {номер сообщения}

PString.'PChar; {адрес строки сообщения}

Result:Longlnt; {поле для записи результата обработки}

End;

Const WM MYMESSAGE= WM_USER; {первый номер из диапазона

пользовательских номеров}

Туре

TForml = class(TForm)

public SecondHandle:Integer; {переменная для хранения

дескриптора второй формы}

end;

Implementation

Procedure TForml. SendButtonClick(Sender: TObject);

Begin

SendMessage(SecondHandle,WM_MYMESSAGE,

LongintfMessageEdit Text),0); {генерация и пересылка сообщения}

End; ...

Вторая форма должна принимать и обрабатывать новое сообщение. Соответственно, класс TForm2 должен включать метод обработки этого сообщения.

Кроме этого, при создании формы ее дескриптор должен запоминаться в первой форме:

Unit Unit2;

Interface

Uses Windows, Messages, Sys Utils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, Until {содержат описание типа сообщения};

Type TForm2 = class(TForm)

MessageEdit: TEdit;

procedure FormCreate(Sender: TObject); public

Procedure WMMyMessage(var Msg:MyMessage);

MESSAGE WM_MYMESSAGE;{метод обработки сообщения}

end;

Var Form2: TForm2;

Implementation {$R *.DFM}

Procedure TForm2.FormCreate(Sender: TObject);

Begin

Forml.SecondHandle:=Handle; {запомнить дескриптор окна второй

формы}

End;

Procedure TForm2. WMMyMessagefvar Msg: My Message);

Begin

MessageEdit.Text:=Msg.PString; {вывести сообщение}

End;

End.

Аналогично для передачи сообщения можно было бы использовать функцию PostMessage:

PostMessage(SecondHandle,WM_MYMESSAGE,

Longint(MessageEdit. Text), 0);

Если с той же целью использовать метод Perform, то необходимо

1) в секции реализации модуля Unitl разрешить использование модуля

Uses Unit2;

2) для передачи сообщения использовать метод объекта Form2:

Form2.Perform (WM_MYMESSAGE,Longint(MessageEdit. Text),0);

При этом поле для хранения дескриптора в TForml становится ненужным.

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

Как уже говорилось, событие реализуется как свойство процедурного типа. Соответственно, определив событие, мы должны предусмотреть его обработчик. В Delphi все события обычно имеют имена, начинающиеся с префикса «Оп»: OnClick, OnCreate и т.д. Для проверки наличия обработчика события используется специальная функция

function Assigned(var Р): Boolean;

Эта функция проверяет, присвоено ли какое-либо значение переменной процедурного типа. Функция возвращает True, если присвоено, и False - в противном случае.

Пример 5.9. Создание события. Создадим событие в обработчике сообщения, рассмотренном в предыдущем примере. МодульишП при этом не изменится.

В модуле Unit2 определим тип обработчика события TPCharEvent, получающего два параметра: стандартный параметр Sender - адрес объекта-

инициатора события и специальный параметр MyString - адрес строки, пересылаемый в сообщении. Затем объявим событие OnPChar и метод - обработчик этого события PCharProc. Подключение метода - обработчика события выполним при создании формы FormCreate.

Unit Unit2;

Interface

Uses Windows, Messages, Sys Utils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, Unitl;

TypeTPCharEvent=procedure(Sender: TObject;MyString:PChar) of object;TForm2 = class(TForm)

MessageEdit: TEdit;

procedure FormCreate (Sender: TObject); private

FOnPChartTPCharEvent; {поле процедурного типа} public

property OnPChartTPCharEvent readFOnMessage

write FOnMessage; {свойство-событие OnPChar } Procedure PCharProc(Sender: TObject; MyStringtPChar);

{обработчик события OnPChar} Procedure WMMyMessage(var Msg: My Message);

MESSAGE WMJMYMESSAGE;

end;

Var Form2: TForm2;

Implementation {$R *.DFM}

Procedure TForm2.FormCreate(Sender: TObject);

Begin

Forml.SecondHandle:=Handle;

OnPChar:= PCharProc; {подключение обработчика события}

End;

Procedure TForm2. WMMyMessage (var Msg: My Message);

Begin

if AssignedfOnPChar) then {если обработчик события определен, то} OnPChar (Self, Msg.PString); {выполнить его}

End;

Procedure TForm2.PCharProc(Sender: TObject; MyString: PChar);

Begin MessageEdit. Text: = MyString; End;

End.

Обработка сообщений компонентов УСЬ. Библиотека УСЬ Ое1рЫ использует достаточно сложные трассы передачи сообщений между компонентами и формой. Это позволяет более гибко организовать их обработку, так как сообщение может быть обработано на любом этапе.

Например, сообщение WMKeyDoun, переданное оконному управляющему элементу класса TEdit, принадлежащему некоторой форме, обрабатывается следующим образом (рис.

5.21).

Сначала сообщение WM KeyDoun поступает в приложение. Получив это сообщение, приложение генерирует сообщение CnKeyDoun для элемента управления редактированием. Получив это сообщение элемент управления редактированием генерирует сообщение CmKeyDoun сначала самому себе, а затем передает его элементу родителю, пока оно не будет передано форме. Если форма возвращает 0 (т.е. отказывается обрабатывать это сообщение), то элемент управления редактированием возвращает 0 сам себе, а затем 0 - приложению.

Получив 0 в качестве результата, приложение передает сообщение WM KeyDoun элементу управления редактированием, который и обрабатывает его по умолчанию.

Управление циклом обработки сообщений. Цикл обработки сообщений приложения в Delphi скрыт в методе Run класса TApplication. Это метод получает управление после инициализации приложения и построения его окон и выполняется следующим образом. Сообщение, извлеченное из очереди методом HandleMessage, передается соответствующему оконному элементу управления для обработки. После завершения обработки сообщения из очереди извлекается следующее сообщение, и т.д., до получения сообщения о

Рис. 5.21. Генерация внутренних сообщений

прекращении работы приложения WMQUIT. При обработке сообщения WMQUIT свойство Terminated устанавливается равным True и цикл обработки сообщений завершается:

... repeat HandleMessage until Terminated;...

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

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

Для того чтобы приложение получило возможность обрабатывать сообщение из очереди, оно должно в цикле длительной обработки периодически вызывать метод ProcessMessages класса TAplication. Этот метод прерывает выполнение приложения для выборки сообщений из очереди, после чего возвращает управление прерванной программе.

Для прекращения длительной обработки приходится использовать специальные приемы, так как просто инициация сообщения WM QUIT (например, при нажатии кнопки завершения приложения) не приводит к завершению приложения до окончания обработки. Это связано с тем, что при вызове ProcessMessages не происходит возврата в цикл обработки сообщений и, следовательно, не анализируется значение свойства Terminated, устанавливаемое при нажатии кнопки завершения приложения.

Пример 5.10. Прерывание длительной обработки. Рассмотрим приложение, которое выводит в окно некоторые числа. Процесс вывода чисел отображается специальным элементом класса TProgressBar, который показывает, какая часть процесса уже завершена. При желании пользователь может остановить процесс нажатием специальной кнопки Прервать (рис. 5.22).

Кнопку Прервать и окно индика-тора будем создавать динамически в процессе выполнения программы. Для организации прерывания обработки добавим в класс TForml свойство Cancel, которое будет устанавливаться равным True при нажатии кнопки Прервать. Проверка этого свойства позволит организовать досрочный выход из цикла по желанию пользователя.

Unit Unitl;

Interface

Uses Windows, Messages, Sys Utils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ComCtrls;

Type

TForml = class(TForm)

StartButton: TButton; ExitButton: TButton; procedure StartButtonClick(Sender: TObject); procedure ExitButtonClickfSender: TObject); procedure ButtonClick(Sender: TObject); private Cancel: Boolean; end;

Var Forml: TForml;

Implementation {$R *.DFM)

Procedure TForml.StartButtonClick(Sender: TObject);

Var ij: integer; ProgressBar: TProgressBar; Button: TButton;

Begin

ProgressBar := TProgressBar. Create(SelJ); {создать вспомогательный объект TProgressBar, объявляя основным Forml} Button:=TButton.Create(Self); {создать вспомогательный объект-кнопку,

объявляя основным Form 1}

ProgressBar.Parent : = Self; {объявить Forml старшим }

ProgressBar.Left: =30; ProgressBar. Top: =45; {определить координаты

изображения}

Button. Parent: =Self; {объявить Forml старшим}

Button.Caption:='IIpepeamb'; {определить название кнопки}

Button. Left: =60; Button. Top: =65; {определить координаты

изображения}

Button.OnClick:=ButtonClick; {подключить обработчик нажатия

кнопки}

for j: =0 to 9 do begin

for i:=l to 10000 do begin

Canvas. TextOut(90,20,IntToStr(i));

Application.ProcessMessages; {прервать обработку, чтобы

проверить наличие сообщений в очереди} if Cancel then break; {если установлено свойство Cancel, то

прекратить обработку}

end;

ProgressBar.StepIt; {вывести в окно изображения ProgressBar очередной закрашенный прямоугольник}

if Cancel then break; {если установлено свойство Cancel, то прекратить

обработку}

end;

ProgressBar. Free; {уничтожить объект TProgressBar}

Button.Free; {уничтожить кнопку TButton}

Canvas. TextOut(70,20, 'Вывод завершен'); end;

Procedure TForml.ButtonClick; {обработчик нажатия на кнопку Прервать} Begin Cancel:=true; End; {устанавливаем свойство Cancel}

Procedure TForml.ExitButtonClick(Sender: TObject);

Begin Close; End;

End.

1.7.

<< | >>
Источник: Г.С.Иванова, Т.Н.Ничушкина, Е.К.Пугачев. Объектно- ориентированное программирование. 2001

Еще по теме Создание и обработка сообщений и событий:

  1. Прием выявления зависимостей сообщения от восприятия юридически значимого события.
  2. СОЗДАНИЕ ВАШЕЙ ПИРАМИДЫ СИЛЫ В ПЯТОМ ИЗМЕРЕНИИ. Сообщение Архангела Михаила от 3 марта 2001 года (передано через Рону Херман).
  3. ПЛАНИРУЯ КАКОЕ-ТО СОБЫТИЕ, ЗАДЕРЖИТЕ В СЕБЕ ЭНЕРГИЮ, А НЕ ВЫПЛЕСКИВАЙТЕ ЕЕ В ЭМОЦИИ ИЛИ В СЛОВА. ЭНЕРГИЯ НУЖНА ДЛЯ ФОРМИРОВАНИЯ ЭТОГО СОБЫТИЯ.
  4. ИНФОРМАЦИЯ: ОБРАБОТКА ПОСЛЕДОВАТЕЛЬНАЯ (
  5. ИНФОРМАЦИЯ: ОБРАБОТКА ПАРАЛЛЕЛЬНАЯ
  6. Статистическая обработка.
  7. ТЕОРИЯ УРОВНЕЙ ОБРАБОТКИ
  8. Обработка материалов
  9. Обработка результатов
  10. ГЛАВА ДЕВЯТАЯ ОБРАБОТКА ИНФОРМАЦИИ В УМЕ
  11. Обработка материала
  12. Алгоритм обработки результатов.
  13. ДАННОЕ: ОБРАБОТКА СТАТИСТИЧЕСКАЯ
  14. Пример обработки протокола.
  15. Обработка ответов
  16. ОБРАБОТКА ВТОРИЧНАЯ
  17. 3.3.4. Методы обработки и анализа данных