- •Объектно-ориентированное программирование
- •Часть 1 классы и объекты
- •Введение
- •1. Классы и объекты
- •Var aLine: tLine;
- •Var aColorLine: tColorLine;
- •2. Методы
- •2.1. Методы-функции и методы-процедуры
- •2.2. Конструкторы и деструкторы
- •Inherited Create;
- •Var TmpFrm: tForm;
- •Var Mem: tMemo;
- •2.3. Классовые процедуры и функции
- •Var s: String;
- •2.4. Скрытый Self
- •3. Видимость компонентов класса
- •4. Наследование
- •4.1. Основные понятия
- •4.2. Наследование полей
- •4.3. Поведение методов при наследовании
- •Var SomeObject: t1;
- •Virtual;
- •Virtual; Abstract;
- •4.4. Иерархия классов
- •4.5. Rtti
- •4.6. Проверка типа
- •4.7. Приведение типа
- •4.8. Указатели на класс
- •Var ObjRef: tObjRef;
- •Implementation
- •X, y, w, h: Integer): tControl;
- •5. Полиморфизм
- •6. Свойства (properties)
- •6.1. Объявление свойств
- •6.2. Объявления свойств-массивов
- •Var I: Byte;
- •6.3. Раздел Read
- •6.4. Раздел Write
- •Inherited Create;
- •Inherited Destroy;
- •6.5. Команды Default, NoDefault и Stored
- •6.6. Команда Index
- •Var aYear, aMonth, aDay: Word;
- •Var aYear, aMonth, aDay: Word;
- •6.7. Команды DispId и Implements
- •6.8. Переопределение свойств при наследовании
- •7. События (events)
- •7.1. Объявление событий
- •IfAssigned(fOnMouseMove) Then fOnMouseMove(Self, Shift, X, y);
- •Vk_return: NumMemo.DoNumStr(l);
- •Vk_return: PostMessage(NumMemo.Handle, wm_user1,1, 0);
- •7.2. Обработчики событий
- •7.3. Делегирование событий
- •Var Objl: tIstClass;
- •7.4. Переопределение стандартных событий
- •Var NewBtn: tNewButton;
Vk_return: NumMemo.DoNumStr(l);
End;
End;
После запуска программы и ввода нескольких строк следует поочередно нажать клавиши Up и Down. Компонент Labell будет отображать номер текущей строки. Если в виртуальном конструкторе убрать строку OnNumStr:=EventNumStr, то вся работа нарушается. Это означает, что работает именно делегированный обработчик.
г) Использование методов сообщений.
Некоторые события в классе TControl помимо корреспондирующих методов включают и объявление методов сообщений, с помощью которых осуществляется вызов корреспондирующих методов. Для этого следует объявить идентификатор пользовательского сообщения и метод сообщения в объявляемом классе. Далее следует представить реализацию метода сообщения, код которого должен включать обращение к корреспондирующему методу. Далее следует посылать сообщение любым известным способом.
Const WM_USER1=WM_APP; // Идентификатор номера сообщения Type
TNumMemo=Class(TMemo) Protected
II Дополнительно объявляем метод сообщения Procedure WMNumStr(Var Msg: TMessage); Message WM_USER1;
Реализация метода сообщения может быть очень проста:
Procedure TNumMemo.WMNumStr(Var Msg: TMessage);
Begin
Forml.NumMemo.DoNumStr(Msg.wParam);
End;
Теперь вызов корреспондирующих методов может быть заменен посылкой сообщений. Приведем несколько различных вариантов посылки сообщения о возникновении события.
Procedure TForml.FormKeyDown(Sender: TObject; Var Key: Word;
Shift: TShiftState);
Begin
Case Key Of
VK_DOWN: IfNuniMeino.NuinStr<NumMeino.Lines.Count+l Then NuniMemo.Perfornt(WM_USERl, 1, 0);
VK_UP: IfNumMemo.NuniStr>l Then
SendMessage(NumMemo.Handle, WM_USER1, -1, 0);
Vk_return: PostMessage(NumMemo.Handle, wm_user1,1, 0);
End;
End;
Более подробно использование сообщений будет рассмотрено во второй части пособия в главе, посвященной сообщениям Windows.
7.2. Обработчики событий
События - это свойства процедурного типа, предназначенные для создания пользовательских реакций на те или иные входные воздействия. Присвоить такому свойству значение - это указать адрес метода, который будет вызываться в момент наступления события (содержит также и адрес объекта с данными). Программист может написать код обработчика события, a Delphi должна адрес этого обработчика события поместить в соответствующее событию поле.
Для создания обработчика событий необходимо дважды щелкнуть мышью по соответствующему событию компонента на странице Events инспектора объектов. Delphi создаст заготовку обработчика события, включая объявление метода в классе TForm и его реализацию с операторными скобками Begin End.
События имеют разные типы в зависимости от происхождения и предназначения. Многие события Delphi возникают, когда поступает соответствующее сообщение Windows. Событие выполняет предварительную обработку сообщения и предоставляет информацию о том, какой объект вызвал это событие, а для специфических событий и дополнительную информацию. Таким образом, вся необходимая информация для написания обработчика имеется в руках программиста.
Фактически процедуры-обработчики событий различаются набором параметров, при этом общим для всех является параметр Sender, указывающий на объект-источник события. Когда происходит событие, связанное с некоторым обработчиком событий, этот обработчик событий получает сообщение для объекта, который породил это событие. Это сообщение передается обработчику события через параметр Sender. По существу, когда обработчик вызван, Sender содержит объект, породивший событие. Поскольку все классы являются потомками от TObject, то экземпляр любого класса может быть присвоен переменной или параметру TObject (полиморфное присвоение). Использование Sender - это способ позволить объекту любого класса передаваться в процедуру обработки события.
С одной стороны, вы не обязаны создавать обработчик для того или иного события, но с другой - вы не можете сделать больше, чем вам позволено.
Чтобы быть совместимым с событием данного типа, обработчик события должен иметь тоже число и тип параметров, что и у указанного типа. Для инсталлированных компонентов Delphi автоматически генерирует обработчик нужного типа для своих событий, а программисту остается только написать код тела обработчика.
Все компоненты, как правило, могут реагировать на события. Хотя многие простые объекты, например текстовые метки (TLabel), способны реагировать только на немногие события, однако все равно есть возможность выбрать следующие действия:
• проигнорировать событие. В этом случае поведение объекта будет определяться обработчиком события по умолчанию и его можно переопределить;
• перехватить событие (trap the event). Тогда необходимо написать собственный обработчик события, изменяющий поведение объекта, принятое по умолчанию.
я) Обработчики уведомительных событий.
Самый простой тип стандартного события TNotifyEvent является уведомительным и не имеет других параметров, кроме Sender, указывающего на объект, вызвавший событие. Тип объявлен в модуле Classes следующим образом:
Type TNotifyEvent=Procedure(Sender: TObject) Of Object;
Наиболее часто используемое событие этого типа OnClick - щелчок мышью по компоненту предусмотрен у большинства компонентов управления. В простейшем случае обработчик этого события может выглядеть следующим образом:
Procedure TForml.FormClick(Sender: TObject);
Begin
ShowMessage('Щелчок мышью по форме!');
End;
б) Обработчики специфических событий.
При возникновении специфического события, операционная система передает не только уведомление (сообщение) о нем, но и некоторую связанную с ним информацию. Например, когда пользователь щелкает мышкой (событие OnMouseDown), операционная система обрабатывает это событие и передает сообщение в окно, которое должно обработать данное событие. При этом дополнительная информация включает координаты нахождения мыши в момент щелчка и сведения о том, какая клавиша мыши была нажата. Это событие имеет тип TMouseEvent, который объявлен в Delphi следующим образом:
Type TMouseEvent^Procediu^Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer) Of Object;
Если вы хотите создать обработчик этого события, то вы должны обратиться к инспектору объектов, найти событие OnMouseDown на странице Events и написать код обработчика этого события. Эту процедуру-обработчик можно использовать, например для вывода на поле формы координат мест
нажатия на левую клавишу мыши, если определить тело этой процедуры следующим образом:
Procedure TForml.FormMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
Begin
Forml.Canvas.Font.Color:=clBIue; // Установка цвет текста Forml.Canvas.Brush.CoIor:=cIBtnFace; // Установка цвета фона Forml.Canvas.TextOut(X, Y, 'X='+IntToStr(X)+' Y='+IntToStr(Y));
End;
Как видно из приведенного примера, программист не обязан использовать всю предоставленную событием информацию.