Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

книги / Объектно-ориентированное программирование

..pdf
Скачиваний:
11
Добавлен:
12.11.2023
Размер:
16.61 Mб
Скачать
5.7. Создание и обработка сообщений и событий
{установить фокус на первый элемент (TabOrder = 0)} {для 8 последовательно расположенных элементов}

Begin

РР: =AxEdit; for i:-1 to 8 do begin

Val(PP.Text, К [PP.Tag],Code); {выполнить преобразование}

if Code<>0 then

{если обнаружена ошибка, то}

begin

{выдать сообщение об ошибке}

S: =chr(ord('A')+PP TabOrder div 2); PPSetFocus;

MessageDlgCKoopdmamu '+S+' введены неверно.', mtError, [mbOk\ 0);

exit;

end;

ifi<>8 then PP:=FindNextControl(PP,truefalse,true) as TEdit; {передать фокус следующему активному элементу}

end;

{если логических ошибок не обнаружено, то запретить установку фокуса ввода на элементы ввода данных и объявить их «только для чтения»}

PP:=AxEdit; for i:=l to 8 do begin

PPEnabled: =false; PPReadonly: =true;

ifi<>8 then PP:=FindNextControl(PP,truefalse, true) as TEdit; end;

В программе использовано также свойство Tag. Это свойство класса TComponent может хранить любую информацию разработчика в виде 32разрядного целого числа. В нашем случае оно хранит индекс вводимой координаты в массиве К, используемом для записи координат.

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

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

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

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

241

5.Объектная модель Delphi Pascal

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

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

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

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

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

Type TMessage=record

Msg.Cardinal;

case Integer o f

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

1:(WParamLo: Word; WParamHi.Word;

LParamLo.Word; LParamHUWord; ResultLo:Word; ResultHi: Word);

end;

end;

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

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

Const M esl = WMJJSER;

Mes2 = WMJJSER+1;

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

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

Procedure wm<HMa метода>(уаг M essage:<nm сообщения>); message <номер сообщ ения^

242

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

Имена методов обработки некоторого сообщения, переопределяемых в иерархии классов, м огут не совпадать: переопределяем ы й метод идентифицируется по совпадающему номеру сообщения, указываемому после специальной директивы message. Номер сообщения обычно задается в виде символического имени, но может указываться и целой положительной константой.

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

type <имя класса>= class <имя класса-родителя> public

Procedure чут<имя метода>(уаг Message: <тип сообщения>); message <номер сообщениям

end;

Если метод обработки сообщения переопределяет уже существовавший в классе-родителе, то обычно в нем программируют только специфические действия по обработке сообщения, а затем вызывают наследуемый метод для выполнения дообрабогки сообщения. Обращение к наследуемому методу при этом осуществляется без указания имени метода (как упоминалось выше, эти имена могут быть различны):

procedure <имя класса>. wm<HMK метода>; begin

Специальная обработка> inherited;

end;

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

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

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

function SendM essage (hW nd:Integer, M es:Cardinal;

W Param , LParam :LongInt):LongInt;

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

243

5.Объектная модель Delphi Pascal

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

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

function PostM essage(hW nd:Integer,M es:Cardinal;

W Param ,Param :LongInt):LongBool;

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

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

procedure Perform (M es:Cardinal; W Param , LParam :LongInt);

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

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

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

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

Передача сообщения.

В МЕЗ

Ifif Прием сообщения 1-1ЙИХ1

Введите сообщение:

 

Текст сообщения

 

Текст сообщения

Передать |рЩуюЩве||

Выход

 

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

244

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

Unit Unitl;

Interface

Type MyMessage=Record

Msg:Cardinal; {номер сообщения} PString:PChar; {адрес строки сообщения}

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

End;

Const WMMYMESSAGE=WM_USER; {первый номер из диапазона пользовательских номеров}

Туре

TForml - class(TForm)

public SecondHandle:Integer; {переменная для хранения дескриптора второй формы}

end; Implementation

Procedure TForml. SendButtonClickfSender: TObject); Begin

SendMessage(SecondHandle,WM_MYMESSAGE, LongintfMessageEdit 7kie(},0};{генерация и пересылка сообщения}

End; . . .

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

Unit Unit2;

Interface

Uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dia­ logs, StdCtrls, {содержит описание типа сообщения};

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

245

5. Объектная модель Delphi Pascal

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

End;

Procedure TForm2. WMMyMessagefvar Msg:MyMessage); Begin

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

End.

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

PostMessage(SecondHandle,WM_MYMESSAGE,

Longint(MessageEdit. Text),0);

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

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

Uses Unit2;

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

Form.2.Perform (WM_MYMESSAGE,Longint(MessageEdit.Texf),0);

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

обработчиков событий.

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

function Assigned(var Р): Boolean;

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

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

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

246

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

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

Unit Unit2;

Interface

Uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dia­ logs, StdCtrls, Unitl;

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

MessageEdit: TEdit;

procedure FormCreate(Sender: TObject); private

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

property OnPChartTPCharEvent readFOnMessage

write FOnMessage; {свойство-событие OnPChar }

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

{обработчик события OnPChar}

Procedure WMMyMessage(var Msg:MyMessage); 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:MyMessage);

Begin

 

 

if Assigned(OnPChar) then

{если обработчик события определен, то}

OnPChar (Self, Msg.PString);

{выполнить его}

End;

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

Begin MessageEdit.Text.^MyString; End;

End.

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

247

5.Объектная модель Delphi Pascal

Наприм ер, сообщ ение W M _K eyD oun, переданное оконному управляющему элементу класса TEdit, принадлежащему некоторой форме,

обрабатывается следующим образом (рис. 5.21).

Сначала сообщение W M KeyDoun поступает в приложение. Получив это сообщение, приложение генерирует сообщение C nK eyD oun для элемента управления редактированием. Получив это сообщение элемент управления редактированием генерирует сообщение Cm K eyD oun сначала самому себе, а затем передает его элементу родителю, пока оно не будет передано форме. Если форма возвращает 0 (т.е. отказывается обрабатывать это сообщение), то элемент управления редактированием возвращает 0 сам себе, а затем 0 - приложению.

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

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

Инициализация внутренних сообщений

 

WM_KeyDour^ Прило­

Сп. КеуРош Г

Эдемент

Cm ChildKi

WMKeyDoun управления ре-

жение

Форма

 

^ датированием

 

 

 

 

Диаграмма внутренних сообщений

 

LWM_KeyDoun

 

 

 

Приложение

-Cn_KeyDoun

 

 

•О

Элемент

 

 

 

 

управления

 

 

 

 

редактированием

CmChildKey

 

0

WMJCeyDoun

Cm_ChildKey -

 

 

 

 

 

 

Форма

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

248

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

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

... repeat HandleM essage

until T erm inated;...

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

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

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

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

новить процесс нажатием специ­

 

 

альной кнопки Прервать (рис. 5.22).

Прерывание обработки.

К нопку

П рервать

и окно

 

 

индика-тора будем создавать

607201

 

динамически в процессе выполнения

 

программ ы . Для организации

— И Г

 

прерывания обработки добавим в

 

класс T F orm l

свойство

C ancel,

Прервать

 

которое будет устанавливаться

 

 

 

равным True при нажатии кнопки

Начать

Выход

Пример 5.10. П реры вание длительной обработки. Рассмотрим при­

ложение, которое выводит в окно некоторые числа. Процесс вывода чисел отоб­

ражается специальным элементом класса TProgressBar, который показывает, какая часть процесса уже завершена. При желании пользователь может оста­

Прервать. Проверка этого свойства

 

позволит организовать досрочный

Рис. 5.22. Вид главного окна приложения

выход из цикла по ж еланию

«Прекращение длительной обработки»

пользователя.

 

249

5. Объектная модель Delphi Pascal

Unit Unitl;

Interface

Uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dia­ logs, StdCtrls, ComCtrls;

type

TForml = class(TForm)

StartButton: TButton; ExitButton: TButton; procedure StartButtonClick(Sender: TObject); procedure ExitButtonClick(Sender: TObject); procedure ButtonClick(Sender: TObject);

private CanceUBoolean; end;

Var Forml: TForml; Implementation

{$R *DFM)

Procedure TForml.StartButtonClick(Sender: TObject);

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

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

Button:=TButton.Create(Self);

{создать вспомогательный объект-кнопку,

ProgressBar.Parent:= Self;

 

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

{объявить Forml старшим }

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

Button.Parent: =Self;

 

 

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

{объявить Forml старшим}

Button.Caption:-Прервать';

 

{определить название кнопки}

Button.Left: =60; Button. Top:=65;

{определить координаты

Button.OnClick:=ButtonClick;

 

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

{подключить обработчик нажатия

 

 

 

кнопки}

forj:= 0to 9 do begin

for i:=l to 10000 do begin

Canvas. TextOut(90,20,IntToStr(i)); Application.ProcessMessages; {прервать обработку, чтобы

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

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

end;

250