procedure WMSize(var message:tWMSize);message WM_Size;

{начальный вариант синтаксиса}

end;

tMyControl2=

class(tMyControl1)

procedure Resize(var Info);message WM_Size; {так тоже можно}

end;

В модуле Messages описаны обработчики практически всех необходимых сообщений Windows. Каждый обработчик имеет идентификатор — целочисленную константу. Например, WM_Size — идентификатор сообщения об изменении размера экранной формы, WM_Move — идентификатор сообщения о ее перемещении и т. д.

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

Самый общий обработчик — метод DefaultHandler, описанный в классе tObject. При обработке сообщения обычно надо вызвать в конце обработчик для прародителя:

procedure MyMsgHandler(var message);message WM_command;

begin

MyProcessing; {некая процедура обработки сообщения}

inherited; {в отличии от конструктора, вызов в самом конце}

end;

При получении объектом от операционной системы Windows сообщения описанного типа (идентификация сообщений происходит автоматически по индексам) вызывается соответствующий обработчик. В описанном выше примере это MyMsgHandler.

Однако обычно нет необходимости обрабатывать сообщения Windows, так как имеется механизм делегирования событий, о котором сейчас пойдет речь.

При необходимости обработки сообщений в обработчике события (см. следующий параграф) надо вызвать метод application. processMessages.

НЕ нашли? Не то? Что вы ищете?

4.15. События и их делегирование. Обработка событий.

События — это свойства процедурного типа. Их название принято начинать с префикса "on". Для описания события некого типа (как описать новый тип события будет рассказано далее) в объекте надо описать поле того же типа, что и свойство. Реально это поле служит указателем на процедуру обработчика события. Кроме того, надо описать собственно свойство:

fOnMyEvent:tMyEvent;

property OnMyEvent:tMyEvent

read fOnMyEvent

write fOnMyEvent;

Тут поле fOnMyEvent является ссылкой на процедуру, с помощью которой осуществляется обработка события. Это поле доступно по чтению и записи! Присваивание свойству значения — это присваивание полю fOnMyEvent указателя на метод, который будет вызываться при наступлении события. Чтение — это метод. Эти методы называются обработчиками событий. Если никакой обработчик не присвоен полю-указателю, то там хранится значение notAssigned.

Пример:

присваивание

application. onActivate:=MyMethod; {MyMethod — имя некой процедуры – обработчика события}

означает, что при запуске приложения будет сначала выполнена процедура MyMethod.

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

Общим для описания типа "событие" является первый параметр Sender типа tObject и ключевая фраза of object после описания типа. Ниже приведен пример задания и использования определенного пользователем типа события tMyEvent:

type

{tNotifyEvent=procedure(Sender:tObject)of object;}

{предопределенное простейшее событие}

tMyEvent=procedure(Sender:tObject;var aMyVar:tMyVar) of object;

tObj1=

class

fOnMyEvent:tMyEvent;

property onMyEvent:tMyEvent

read fOnMyEvent

write fOnMyEvent;

end;

tObj2=

class

procedure MyEventProcessing1(Sender:tObject;

var aMyVar:tMyVar);

procedure MyEventProcessing2(Sender:tObject;

var aMyVar:tMyVar);

end;

...

var aObj1:tObj1;

aObj2:tObj2;

myKey:Boolean;

begin

aObj1:=tObj1.Create;

aObj2:=tObj2.Create;

...

if MyKey

then

aObj1.onMyEvent:=aObj2.MyEventProcessing1

else

aObj1.onMyEvent:=aObj2.MyEventProcessing2;

...

end.

При делегировании можно присваивать методы других классов! Даже не являющихся потомком и прародителем! Но при этом должно быть полное соответствие списков параметров обработчиков событий со списком параметров процедурного типа события.

4.16. Методы класса и указатели на класс.

Некоторые методы бывает нужно вызывать без создания экземпляра класса (например, для получения информации о имени класса, размере экземпляра класса и т. п.). Такие методы называются методами класса - в C++ и Java они называются статистическими методами (не путать со статистическими методами в смысле TP и Delphi!). Методы класса имеют перед словами procedure или function ключевое слово class (за исключением конструкторов, которые также являются методами класса, но для которых синтаксис, как мы знаем, другой):

type

tMyObj=

class

class function MyGetSize:String;

end;

var aMyObj:tMyObj;

begin

...

Label1.caption:=tMyObj. MyGetSize; {вызов метода класса tMyObj}

aMyObj:=tMyObj. Create; {вызов другого метода класса tMyObj}

Label2.caption:=aMyObj. MyGetSize; {вызов метода класса с

экземпляром класса}

...

end;

Возможно описание указателя на класс с помощью ключевой фразы class of. Это иногда требуется в программах, использующих сложную иерархию объектов, для унифицированного динамического создания, копирования и уничтожения объектов, принадлежащих разным классам. В модуле SysUtils указатель на tObject описан так:

type tObject=class;

tClass=class of tObject;

Имеются следующие важнейшие стандартные функции классов, определенные в tObject:

·  class function ClassName:string — возвращает имя класса, вызвавшего объект;

·  class function ClassParent:tClass — возвращает указатель на класс прародителя;

·  function ClassType:tClass — возвращает указатель на класс вызвавшего объекта;

·  class function ClassInfo:Pointer — возвращает указатель на структуру (запись), содержащую информацию о классе.

Также имеется ряд других стандартных функций классов.

Пример использования указателя на класс:

tMyObj=

class

...

end;

tMyObjRef=class of tMyObj;

tChildObj=

class(tMyObj)

...

end; {/class}

var

aMyObjRef:tMyObjRef;

aMyObj:tMyObj;

aChildObj:tChildObj;

После такого объявления можно проводить присваивания такого рода:

if...

then

aMyObjRef:=tMyObj; {при выполнении условия aMyObjRef

стало типом tMyObj}

else

aMyObjRef:=tChildObj; {иначе - типом tChildObj}

aMyObj:=aMyObjRef. Create; {создали объект, тип которого

определяется aMyObjRef}

Без указателей на класс пришлось бы писать вызовы конструктора Create внутри оператора if по отдельности для tMyObj и tChildObj.

Указатели на класс удобно использовать совместно с булевским оператором is, возвращающим true в случае совместимости по присваиванию объекта, указанного перед is, с экземпляром класса, упомянутого после is:

if aMyObj is tAnyObj then...;

Например, если aMyObj – кнопка типа tBatton, а в качестве tAnyObj написано tWinControl, оператор is возвратит true. Если же aMyObj – метка типа tLabel, он возвратит false, так как tLabel является потомком tControl, но не tWinControl.

Существует также специальный вариант приведения типов для объектов при помощи оператора as:

aObj1:=aObj2 as tObj1; {aObj2 вызывается в точности как экземпляр его

класса-прародителя tObj1}

aMyVar:=(aMyObj as tMyRecordObj).Data; {тут Data - свойство;

если это обычное поле, приведение не имеет смысла}

Понятно, что такое приведение возможно только к типу класса-прародителя.

Этот тип приведения очень часто используется в обработчиках событий. Например, если мы хотим изменить координату “x” элемента типа tImage, перетаскиваемого “мышью”, то в обработчике onDragOver элемента, над которым мы его перетаскиваем, надо написать

If Sender is tImage then( Sander as tImage).x=x;

При этом написать Sender. x=x нельзя, так как типом Sender является tObject, а в нем поле x не определено.

4.17. Дополнительные возможности Object Pascal.

4.17.4. Функции

а) могут возвращать значения определенных пользователем типов, включая сложные;

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

4.17.5. Оператор CASE.

Значения вариантов (в том числе диапазоны) не могут пересекаться. Расположение вариантов в порядке возрастания позволяет компилятору оптимизировать код.

4.17.6. Открытые массивы.

Открытым массивом называется массив, используемый как формальный параметр процедуры, длина которого задается не в месте задания процедуры, а при ее вызове. При этом при ее вызове могут использоваться массивы разной длины.

Замечание: если нужен массив переменной длины, для этих целей используют список (мы уже знаем, как это делать). Правда, работа с массивом требует меньше памяти и идет быстрее, чем со списком. В Delphi начиная с версии 2.0 одномерные открытые массивы можно использовать без описания соответствующего типа. С версии 4.0 поддерживаются двумерные открытые массивы. Имеются предопределенные функции Low и High, в качестве параметра которых подставляется имя массива. При этом Low возвращает номер первого элемента, а High — последнего. Надо отметить, что в Delphi (как и в С++, JavaScript и Java) все номера начинаются с 0, а не с 1.

Пример:

program ArcDemo; {MyData - открытый массив}

function Mean(MyData:array of Real):Real;

var i:Integer;

begin

Result:=0;

for i:=Low(MyData)to High(MyData)do {цикл от первого до

последнего элемента}

Result:=Result+MyData[i];

Result:=Result/(High(MyData)-Low(MyData)+1);

end;

var X:Real;

begin

X:=mean([1,9,9,7]); {задаем массив путем перечисления элементов}

Из за большого объема этот материал размещен на нескольких страницах:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17