Студопедия

КАТЕГОРИИ:


Архитектура-(3434)Астрономия-(809)Биология-(7483)Биотехнологии-(1457)Военное дело-(14632)Высокие технологии-(1363)География-(913)Геология-(1438)Государство-(451)Демография-(1065)Дом-(47672)Журналистика и СМИ-(912)Изобретательство-(14524)Иностранные языки-(4268)Информатика-(17799)Искусство-(1338)История-(13644)Компьютеры-(11121)Косметика-(55)Кулинария-(373)Культура-(8427)Лингвистика-(374)Литература-(1642)Маркетинг-(23702)Математика-(16968)Машиностроение-(1700)Медицина-(12668)Менеджмент-(24684)Механика-(15423)Науковедение-(506)Образование-(11852)Охрана труда-(3308)Педагогика-(5571)Полиграфия-(1312)Политика-(7869)Право-(5454)Приборостроение-(1369)Программирование-(2801)Производство-(97182)Промышленность-(8706)Психология-(18388)Религия-(3217)Связь-(10668)Сельское хозяйство-(299)Социология-(6455)Спорт-(42831)Строительство-(4793)Торговля-(5050)Транспорт-(2929)Туризм-(1568)Физика-(3942)Философия-(17015)Финансы-(26596)Химия-(22929)Экология-(12095)Экономика-(9961)Электроника-(8441)Электротехника-(4623)Энергетика-(12629)Юриспруденция-(1492)Ядерная техника-(1748)

Interface




Begin

МЕТОДЫ

Методы служат для обработки информации, содержащейся в полях. Доступ к полям может осуществляться без дополнительных (формальных) параметров. Формальные параметры у методов обычно служат для обмена информацией с другими классами.

В классе метод только объявляется. Описывается он в разделе реализа­ции модуля (секция Implementation). При описании указывается имя класса-владельца и через точку имя метода. Например,

 

Procedure TMyClass.AMethod(Param:AType); Begin

end;.



Внутри begin... end можно вызывать любые методы предков с указа­нием имени предка. Ближайший предок, имеющий такое же имя, как у дан­ного метода, может вызываться с помощью зарезервированного слова inher­ited.

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

• Procedure;

• Function;

• Constructor - вид Procedure, служащий для построения объекта, инициализации полей и правильного вызова так называемых виртуальных методов;

• Destructor - вид Procedure, служащий для освобождения памяти, т.е.
разрушения объекта.

При построении объекта автоматически объявляется дополнительная пе­ременная Self. Тип этой переменной совпадает с классом, породившим дан­ный объект. Переменная Self является локальной и определена только внут­ри данного экземпляра класса. При необходимости внутри любого метода можно воспользоваться этой переменной.

ВИДЫ МЕТОДОВ

Методы бывают разных видов. По умолчанию методы являются стати­ческими (Static) Методы в разных классах могут иметь одинаковые имена. При вызове методов обязательно указывается через точку имя объекта, вы­звавшего данный метод. Например, пусть класс AClassType породил объект AnObject. Если вызывается метод AStaticMethod, то вызов записывается так: AnObject.AStaticMethod;.

Если в классе AClassType непосредственно такого метода нет, то вызы­вается ближайший по линии наследования метод с заданным именем.

Недостаток статических методов заключается в следующем. Пусть ме­тод AStaticMethod вызывает внутри себя другой метод, например Second-Method. Пусть по линии наследования определено несколько методов с име­нем SecondMethod. В данном случае AStaticMethod вызовет ближайший по программному описанию SecondMethod, независимо от того объекта, который вызвал метод AStaticMethod.Таким образом, при использовании статических методов нельзя конкретно указать, какой из имеющихся по ли­нии наследования нескольких методов с одним именем требуется вызвать.

МЕТОДЫ VIRTUAL И ПОЛИМОРФИЗМ

Особенности виртуальных (Virtual) методов рассмотрим на примере. Пусть объявлен класс AClass. Этот класс имеет потомка, который, в свою очередь, также имеет потомка, например AClass -> BClass -> CClass.


Пусть AClass содержит метод Drag, который служит для рисования не­которой геометрической фигуры. При этом внутри метода Drag вызывается метод Show для рисования заданной фигуры. Пусть метод show реализован в каждом из трех указанных классов для рисования точки (класс AClass), ок­ружности (BClass) и квадрата (CClass). Метод Drag содержится только в AClass. Так как нужная фигура вызывается для рисования из метода Show, нет необходимости дублировать его в других классах. Пусть заданы три объ­екта: Var A:AClass; В:Bclass; С:CClass.

Пусть с помощью соответствующих конструкторов эти объекты созда­ны. Пусть вначале все три метода Show объявлены как статические. Запишем вызов на рисование геометрической фигуры: с. Drag;.

Рассмотрим, какая фигура изобразится в данном случае. По линии на­следования от CClass, вызвавшего Drag, в классе AClass найдется метод Drag. При вызове происходит обращение к Show. В данном случае вызовется ближайший к Drag метод, находящийся в классе AClass, т.е. изобразится точка. Вызвать метод Show из класса BClass для рисования окружности или вызвать Show из CClass и нарисовать квадрат с помощью статических мето­дов нельзя.

Итак, в данном случае ставится следующая задача. Вызов C.Drag; дол­жен нарисовать квадрат, B.Drag; - окружность, соответственно A.Drag; -точку, т.е. метод Show для С.Drag должен вызываться из класса CClass, для B.Drag- из класса BClass, а для A. Drag- из класса AClass. Такая задача решается с помощью виртуальных методов show. Тогда вызов show будет определяться конкретным фактическим объектом.

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

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

Свойство одного и того же метода вести себя по-разному называется по­лиморфизмом (многоформным). Например, метод Drag, указанный в приве­денном выше примере, может построить точку, окружность или квадрат. Для реализации полиморфизма используются виртуальные методы.


Итак, наряду с инкапсуляцией и наследованием, третьей особенностью типа класс по сравнению с другими типами является полиморфизм.

МЕТОДЫ DYNAMIC

Механизм Dynamic доступа к другим методам подобен механизму Vir­tual. В обоих случаях адрес нужной процедуры или функции определяется фактическим объектом. Отличие заключается в том, что в данном случае строится таблица динамических методов. Обращение к этой таблице про­исходит медленнее, чем к таблице виртуальных методов, зато объем про­граммы получается меньше. Методы Dynamic целесообразно использовать, когда класс имеет множество потомков, а число переопределяемых методов небольшое.

МЕТОДЫ MESSAGE

Методы Message - обработки сообщений - представляют собой осо­бую форму динамических методов. Обработчики сообщений всегда являют­ся процедурами. Для ускорения поиска в таблице динамических методов после ключевого слова Message записывается константа целого типа, яв­ляющаяся индексом нужного метода. В обработчике сообщений имеется один параметр Var. Методы Message - это одно из звеньев взаимодействия компонентов Delphi с Windows. Объявление обработчика сообщений выгля­дит приблизительно так: Procedure Handle_WM_Paint(var Msglnfo); Message WM_Paint;.

Для поиска нужного адреса в таблице динамических методов в данном примере записана константа WM_Paint. Многие константы для Message за­резервированы за конкретными сообщениями Windows и выбирать их про­извольно нельзя. Указанная константа поиска данного сообщения Windows может быть переопределена в каком-либо предке по линии наследования для данного объекта. Если константа Message не найдена, то вызывается метод обработки сообщений, заданный по умолчанию.

МЕТОДЫ ABSTRACT

Обычно методы создаются для выполнения каких-то конкретных дейст­вий. Если по какой-либо причине это выполнить не удается, метод в классе может быть зарезервирован с обязательным переопределением его в классах потомков. Такой метод помечается ключевым словом Abstract. Если абст­рактный метод не переопределен, то вызов такого метода приводит к вызову специальной процедуры Abstract, которая генерирует исключительную си­туацию. Абстрактным не может быть статический метод, так как статиче­ские методы нельзя переопределять. Например,


Type TmyParent=class

Procedure AMethod;virtual;abstract; End; TmyClass=class(TmyParent)

Procedure AMethod;override; End;

МЕТОДЫ OVERRIDE

Как указано выше, зарезервированным словом Override помечаются пе­реопределенные виртуальные или динамические методы (пример выше).

МЕТОДЫ CLASS

Исходное назначение методов - определять поведение экземпляров объ­ектов какого-либо класса. В некоторых случаях необходимо иметь ситуа­цию, когда поведение, задаваемое для метода, не должно зависеть от реально существующего объекта. Такая ситуация возникает с методом, который, на­пример, должен возвращать имя класса. В этом случае метод помечается ключевым словом Class. В отличие от других команд, таких, как Dynamic, Virtual и т.д., слово Class ставится перед заголовком метода, например Class Procedure AMethod;.

ПРИМЕР ПРИЛОЖЕНИЯ 14

Рассмотрим пример по использованию конструкторов и деструкторов в объектах. Кроме того, посмотрим, как можно использовать указатели на ме­тоды и методы class.

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

ДИНАМИЧЕСКОЕ СОЗДАНИЕ КОМПОНЕНТОВ

Пусть имеется форма, у которой есть только обработчик события Mouse Down, с помощью которого можно динамически строить кнопки, на­жимая на левую клавишу мыши. Закрепляется каждая кнопка на форме в позиции координат точки, в которой была нажата клавиша мыши. Вот код данного обработчика:

procedure TForm1.FormMouseDown(Sender:TObject; Button:

TMouseButton; Shift: TShiftState; X, T: Integer); Var Btn:Tbutton;


Btn:=TButton.Create(self)

Btn.Parent:=self;

Btn.Left:=x;

Btn.Top:=y;

Btn.Width:=Width+50;

Btn.Caption:=Format('Кнопка x,y= %d,%d',[x,y]); end;.

В Delphi ключевое слово self используется, например, когда нужно яв­но обратиться к текущей форме в одном из ее методов.

Динамическое создание компонентов является тем случаем, когда требу­ется передать конструктору create параметр Owner (указать владельца соз­даваемого объекта), а затем присвоить то же значение свойству Parent (ука­зать родителя). В обоих случаях нужно передавать имя текущей формы (не всегда параметры Owner и Parent совпадают, как в данном случае). Таким образом, обработчик выше будет корректно работать, если параметр self заменить на Form (пусть такое имя имеет переменная типа Form). Следу­ет отметить, что код, приведенный выше, обычно записывается с использо­ванием оператора with:

procedure TForm1.FormMouseDown(Sender: TObject/Button:

TMouseButton; Shift: TShiftState; X, Y: Integer); begin

with TButton.Create(self) do begin Parent:=self; Left:=x; Top:=y;

Width:=Width+50;

Caption:=Format('Кнопка x,y= %d,%d,[x,y]); end; end;.

Ниже приводится объявление модуля, используемого в данном случае:

unit priml4;

uses Windows, Messages, SysUtils, Classes, Graphics,

Controls, Forms, Dialogs, StdCtrls, ExtCtrls, Menus; Type

TForm1 = class(TForm)

procedure FormMouseDown (Sender: TObject;Button: TMouseButton;Shift: TShiftState; X, Y: Integer);

end; var Form1: TForm1;.

Вариант решения примера представлен на рис 34.

 
 

 


 

Рис.34

ИСПОЛЬЗОВАНИЕ КЛАССА СО СЧЕТЧИКОМ ОБЪЕКТОВ

Пусть в примере 14 будем строить кнопки некоторого собственного ти­па, унаследованного от типа TButton. Построим для этих целей класс, в ко­тором предусмотрим счетчик создаваемых объектов.

Для хранения числа создаваемых объектов понадобится переменная це­лого типа. Объявим ее в секции implementation: var CountBtns: integer = 0;. Эта переменная содержит общую информацию о форме и представ­ляет данные модуля, поэтому она не включена как поле в класс. Для доступа к такой информации понадобится метод класса. Теперь представим объявле­ние нашего класса:

type

TMyButton=class(TButton) public

Constructor Create{AOwner:TComponent); override;

Destructor Destroy; override;

class function GetCount:integer; end;.

Увеличение счетчика объектов предусмотрим при вызове конструктора, уменьшение - при вызове деструктора. Для построения объектов и их раз­рушения, естественно, будем использовать стандартные методы. Ниже при­водятся описания деструктора и конструктора:

constructor

TMyButton.Create (AOwner: TComponent); begin

inherited;

Inc(CountBtns); end;

destructor TMyButton.Destroy; begin

dec(CountBtns);

inherited; end;.

 




Так как переменная countBtns объявлена в секции implementation, об­ратиться к ней извне модуля нельзя. Только метод класса позволяет нам про­читать ее текущее значение:

class function TMyButton.GetCount: integer; begin

Result:=CountBtns; end;.

Теперь можно создавать объекты нашего нового типа TMyButton, не­много изменив приведенный выше код обработчика FormMouseDown:

procedure TForm1.FormMouseDown(Sender: TObject; Button:

TMouseButton; Shift: TShiftState; X, Y: Integer);

begin

with TMyButton.Create(self) do begin

Parent:—self;

Left:=x;

Top:=y;

Width:=Width+60;

Caption:=Format{'%d кнопка x,y= %d,%d',[GetCount,x,y]); end;.

Класс-функция GetCount может вызываться, в отличие от обычных ме­тодов, как из объекта (в обработчике FormMouseDown), так и из класса. На­пример, добавим таймер (компонент TTimer) на форму и обеспечим при срабатывании таймера изменение заголовка формы с помощью следующего обработчика события OnTimerr

procedure TForm1.Timer1Timer(Sender: TObject);

begin

Caption:=Format('Кнопок на форме %d',[TMyButton.GetCount]);

end;.

В результате решения получим, например, следующий вариант (рис. 35).

ОТСЛЕЖИВАНИЕ РАЗРУШЕНИЯ ОБЪЕКТОВ

Проследим за разрушением объектов на форме. Очевидно, это можно увидеть в секциях initialization и finalization, т.е. после того, как форма начнет разрушаться.

initialization

MessageBox(0,PChar(Format('На форме %d кнопок', [TMyButton.GetCount])),'Инициализация',mb_ok);

finalization

MessageBox(0,PChar(Format('На форме %d кнопок', [TMyButton.GetCount])),’Финиш,mb_ok);.

В данном случае использовалась функция Windows API MessageBox, так как при разрушении формы доступ в секции finalization ко многим функциям Delphi невозможен. Запуская данную программу на выполнение, получим два сообщения до построения и после разрушения формы.

СОБЫТИЯ

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

Рассмотрим вариант переопределения методов послания уведомления о событии. Такие методы реализуются в разделе Protected. Поэтому потомки тех встроенных классов, в которых реализуются такие методы, могут делать доступными их для пользователя. Например, рассмотрим, как переопределя­ется метод послания уведомления о событии Click для кнопки, одновремен­но изменяя ее заголовок на строку, в которую записано текущее время.

 

TtimeButton=class(Tbutton) Protected

Procedure Click; override; End;

………………………..

Procedure TtimeButton.Click;

 

Inherited Click;

Caption:=DateTimeToStr(Now); End;.

 


Рис.35



Методы послания уведомления о событии являются указателями на ме­тод, которые вызываются в случае, когда компонент получает сообщение от Windows о том, что произошло некоторое событие, воздействующее на дан­ный компонент. Обработчики событий представляют собой свойства, ко­торые выполняют чтение и запись в указатели на метод. Например, рассмот­рим фрагмент, взятый из класса TControl, содержащегося в исходном коде VCL. Имена обработчиков событий по соглашению содержат префикс On. Вначале объявляется событие; TNotifyEvent = procedure (Sender:TObject) of object;. Далее объявляется класс, содержащий поля данно­го типа, и обработчики событий, работающие с этими полями.

 
 

Tcontrol=class(TComponent) Private

FOnClick: TNotifyEvent;

………………….

Ptotected

Property OnClick: TnotifyEvent read FOnClick write FOn­Click;

……………………………………

end;.

При создании собственных обработчиков необходимо научиться строит методы посылки уведомления о событии. Эти методы должны уметь полу­чать и обрабатывать сообщения Windows, что возможно сделать с помощью методов вида Message.

УКАЗАТЕЛИ НА МЕТОДЫ

Этот тип данных представляет собой ссылку (указатель) на метод. Ука­затель на метод содержит два адреса: одна ссылка на адрес кода метода, дру­гая - на адрес экземпляра объекта - представляет собой скрытый параметр self. Адрес self представляет собой в данном случае адрес расположения дан­ных, принадлежащих конкретному объекту.

Указатели на методы реализуют один из принципов компонентной технологии - делегирование. Если кто-то написал класс, у которого есть по­ля в виде указателей на методы, например,

Туре

TNotifyEvent=procedure(Sender:Tobject) of object; TMyButton=class

OnClick: TNotifyEvent; End;

,то можно менять поведение построенных (даже скомпилированных) объек­тов этого типа, просто присваивая этим указателям новые методы. Напри­мер, пусть объявлено:


туре

TForm1=class(TForm)

Procedure OnButton1Click(Sender:Tobject); Button1:MyButton; End;.

Теперь при построении компонента на форме можно делегировать обработ­чик OnButton1click из TForm1 в MyButton путем следующего присваива­ния: MyButton.OnClick:=Form1.OnButton1click;.

ПРИМЕР ПРИЛОЖЕНИЯ 15

Продолжим рассмотрение примера 14. Попытаемся не только динамиче­ски создавать новые объекты, но и разрушать их также динамически. Выбе­рем, что уничтожение очередного объекта будет наступать, как только поль­зователь нажмет на клавишу Backspace (#8). Для реализации этой идеи по­надобятся указатели на методы.

В данном случае динамически созданный объект для своего уничтоже­ния должен отслеживать нажатие клавиши #8. Для этих целей может слу­жить событие OnKeyPress. Этому событию надо делегировать собственное событие. Прежде всего, необходимо убедиться, что оно объявлено как указа­тель на метод, иначе делегирование невозможно. В справочной системе Del­phi можно найти следующее объявление:

TKeyPressEvent=procedure(Sender:Tobject;var key:char) of object;

Property OnKeyPress: TKeyPressEvent;.

Таким образом, для делегирования необходимо создать свою процедуру. В классе TForm1 добавим собственный обработчик: Procedure MyButtonKeyPress(Sender:Tobject; var key:Char);.

Кроме того, в класс TForm1 необходимо добавить переменную для запи­си того динамически построенного метода, который подлежит удалению, так как может удаляться не только текущий объект, но и предыдущий (если но­вые объекты не создаются). Добавим такое объявление в секцию Private ToDestroy:TMyButton;. Теперь определим новую процедуру обработки события OnKeyPress:

Procedure TForm1.MyButtonKeyPress(Sender: TObject;

var Key: Char); begin

if key=#8 then ToDestroy:=Sender as TButton;

end;.


Эта процедура не уничтожает, а запоминает подлежащий уничтожению объект. Чтобы она работала, необходимо при создании кнопки делегировать наш обработчик, записывая OnKeyPress:=MyButtonKeyPress;.

Допишем еще одну строку для установки фокуса на текущий объект SetFocus;, т.е. после удаления очередного объекта необходимо перемес­тить фокус ввода на предыдущий объект.

Удаление кнопки реализуем в обработчике onTimer. Полный текст про­граммы приводится ниже.

unit priml5;

interface

uses Windows, Messages, SysUtils,Classes, Graphics,

Controls, Forms, Dialogs, StdCtrls, ExtCtrls; type

TMyButton=class(TButton) public

Constructor Create (AOwner:TCoraponent); override; Destructor Destroy; override; class function GetCount:integer; end;

TForm1 = class(TForm) Timer1: TTimer;

procedure FormMouseDown(Sender: TObject; Button:

TMouseButton; Shift: TShiftState; X, У: Integer); procedure Timer1Timer(Sender: TObject};

private

ToDestroy:TMyButton;

Procedure MyButtonKeyPress{Sender:Tobject; var key:Char); end;

var Form1: TForm1; implementation

var CountBtns: integer =0; {$R *.dfm}

Constructor TMyButton.Create(AOwner: TComponent); begin

inherited; Inc(CountBtns);

end;

 

Destructor TMyButton.Destroy; begin

.dec(CountBtns); inherited;

end;

class function TMyButton.GetCount: integer; begin

Result:=CountBtns; end;


procedure TForm1.MyButtonKeyPress(Sender: TObject; var Key: Char); begin

if key=#8 then ToDestroy:=Sender as TMyButton;

end;

procedure TForm1.FormMouseDown(Sender: TObject; Button:

TMouseButton; Shift: TShiftState; X, Y: Integer);

Begin

with TMyButton.Create(self) do begin Parent:=self;

Left:=x;

Top:=у;

Width:=Width+60;

 

Caption:=Format('%d кнопка x,y= %d,%d', [GetCount,x, y]); OnKeyPress:=MyButtonKeyPress; SetFocus; end; end;

procedure TForm1.Timer1Timer(Sender: TObject); begin

if Assigned(ToDestroy) then begin SelectNext{ToDestroy,false,true); ToDestroy.Free;

ToDestroy:=nil;

end;

Caption: =Format {'Кнопок %d'., [TMyButton. GetCount]); end; end.

Вариант решения получим таким же, как на рис. 35. Однако в данном варианте, нажимая неоднократно на клавишу Backspace, можно удалить все кнопки, построенные на форме.

Все переменные типа класс (например, ToDestroy) по сути, являются указателями, поэтому для проверки, существует ли тот или иной объект, применяется функция Assigned (обработчик Timer1Timer), которая прове­ряет, равна переменная значению "пустой указатель" (т.е. nil) или нет.

ТИПЫ ССЫЛКИ НА КЛАСС

Такой программный элемент, как тип обычной переменной, представ­ляющий собой правила обращения с теми или иными переменными, сущест­вует только во время компиляции программы. Эти правила не могут изме­ниться во время выполнения программы. Типы ссылки на класс, которые синтаксически объявляются как class of TMyClass, позволяют нарушить указанные правила. С помощью этих типов можно обращаться к объектным типам во время выполнения программы. Для некоторого заданного типа


объектный тип - это значение, которое можно записать в переменную типа ссылки на класс. Во время выполнения программы в разных ее участках пе­ременной данного типа можно присваивать в качестве значения различные объектные типы и, таким образом, строить нужные объекты, вызывая или иной виртуальный конструктор.

СВОЙСТВА

Свойства представляют интерфейс с внутренними полями данных того или иного объекта. Внутренние поля обычно объявляются в разделе Private. Их имена, как правило, начинаются с буквы F, например поле FColor. Соот­ветственно свойство, с помощью которого осуществляется доступ к задан­ному полю FColor, имеет имя Color. Свойства могут объявляться с различ­ной степенью доступа. Если требуется, чтобы они отображались в окне ин­спектора объектов, их объявляют в разделе Published.

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

• Simple - простые свойства;

• Enumerated - перечисляемые;

• Set - множества;

• Object - объектного типа;

• Array - индексированные свойства.

Разные типы свойств по-разному отображаются в инспекторе объектов и имеют свои собственные редакторы для изменения значений свойств. Далее рассмотрим синтаксис записи различных видов свойств.

СВОЙСТВА SIMPLE

Простые свойства включают числовые, символьные и строковые типы данных. Наиболее часто используются свойства типа integer и string. Напри­мер, свойства Width, Height имеют тип integer, свойство Caption имеет тип string. Объявим для демонстрации синтаксиса записи простых свойств сле­дующий класс:

Туре

TSimple=class(TCustomControl) Private

PString: string; Published

Property StringProp:string read FString write FString; end;

Как следует из этого примера, свойства имеют тип поля, в котором хра­нится значение данного свойства. Кроме того, для свойства необходимо указать

 

 


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

СВОЙСТВА ENUMERATED

Свойства enumerated определяются типом перечень и логическим ти­пом Boolean. Обычно все возможные значения данного типа свойств некото­рым способом помечаются, например, как в объявлениях ниже:

туре

TEnumProp=(epZero, epOne, epTwo, epThree); TEnum=class(TCustomControl) Private

FEnumProp: TEnumProp; Published

Property EnumProp:TEnumProp read FEnumProp write FEnumProp; end;.

СВОЙСТВА SET

Элементы свойства Set (множество) в инспекторе объектов заключают­ся в квадратные скобки. Для развертывания в инспекторе объектов элемен­тов базового множества, включающего в себя все возможные варианты, имеется знак "+", расположенный слева от наименования свойства. Вклю­чить или не включить тот или иной элемент из базового множества в рабо­чее множество выбирают путем указания true или false. Рабочее множество определяет значение данного свойства. Рассмотрим пример объявления свойства Set. При этом используется тип TEnumProp, объявленный выше.

TSetProp=set of TEnumProp TSetClass=class(TCustomControl) Private

FSetProp:TSetProp; Published

Property SetProp:TsetProp read FSetProp write FSetProp; End;.

СВОЙСТВА OBJECT

Свойства Object в инспекторе объектов помечаются или знаком "+" или кнопкой с многоточием. Например, свойство Font имеет объектный тип. Дня того чтобы привести пример объявления свойства объектного типа, не­сводимо предварительно сформировать объект какого-либо класса и вы-

. 129


брать предка для этого класса. На практике в большинстве случаев в качест­ве предка выбирается встроенный класс TPersistent. Объявим класс, который будет определять далее в примере тип свойства.

Туре

T0bjectDop=class{TPersistent) Private

FMyInt:integer; Public

Property MyProp:integer read FMyInt write FMyInt; End;.

В данном случае нужно решить одну проблему. Объявленный выше класс (TObjectDop) должен войти как составная часть в класс, который должен будет содержать свойство заданного объектного типа TObjectDop. Соответственно потребуется задавать этому свойству значение, а это означа­ет, что потребуется объект типа TObjectDop, для которого необходимо обеспечить выделение памяти и освобождение памяти. Стандартных мето­дов выделения и освобождения памяти в данном случае недостаточно. Для выделения памяти создадим конструктор Create, а для высвобождения па­мяти - деструктор Destroy.

 

туре

TObjectProp=class(TCustomControl) Private

FObjectProp: TObjectDop; Public

Constructor Create(AOwner:TComponent);override; Destructor Destroy;override;

Published

Property ObjectProp: TObjectDop

read FObjectProp write FObjectProp; End;.

Конструктор и деструктор объявлены с командой Override. Это означа­ет, что в данном классе переопределяются имеющиеся по линии наследова­ния стандартные виртуальные конструктор Create и деструктор Destroy. Определим эти методы.

Constructor TObjectProp.Create(AOwner:TComponent); begin

Inherited Create(AOwner);

FObjectProp:= TObjectProp.Create;

end;

Destructor TObjectProp.Destroy; Begin

FObjectProp.Free;


Inherited Destroy; End;.

Необходимо обратить внимание на то, в какой последовательности вы­зываются стандартные методы с помощью процедуры inherited.

СВОЙСТВА ARRAY

Свойства Array позволяют создать очень похожие на массивы индекси­рованные свойства, которые отличаются от обычных массивов по двум ос­новным аспектам:

• свойства типа Array могут индексироваться строковым значением;

• свойства типа Array могут получать доступ только к одному элементу
за одно чтение.

В окне Object Inspector эти свойства помечаются кнопкой с многоточием (…). Для изменения значений свойств данного вида вызывается специальный редактор. Ниже приводится пример объявления индексированного свойства.

Туре

 

Str7=string[7];

TMas=array [1..3] of str7; TMasClass=class(TCustomControl)

Private

FMasProp: TMas;

 

Function GetMasInt(pIndex:integer):string;

Function GetMasStr(pIndex:string):integer; Public

Constructor Create(AOwner:TComponent);override;

Property MasPropInt[Index:integer]:string read GetMasInt;

Property MasPropStr[Index:string]:4integer read GetMasStr; end;.

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

Constructor TMasClass.Create(AOwner:TComponent); begin

FMasProp[1]:='one';

FMasProp[2]:='two';

FMasProp[3]:='three'; End;

TMasClass.GetMasInt{pIndex:integer):string;


begin

result: = 'unknown';

if pIndex in [1..3] then result:= FMasProp[pIndex];

end;

Function TMasClass.GetMasStr(pIndex:string):integer;

var x:integer; begin

result:=-l; for x:=l to 3 do

if Uppercase(BMasProp[x])=Uppercase(pIndex) then begin

result:=x;

exit;

end;

end;.

Здесь первая функция может читать значение свойства при заданном ин­дексе, а вторая может использоваться для поиска индекса по заданному зна­чению.

ЗАДАНИЕ НАЧАЛЬНЫХ ЗНАЧЕНИЙ СВОЙСТВАМ

Когда создаются свойства, они первоначально получают нулевые или неопределенные (в зависимости от типа свойства) значения. Если необходи­мо задать свойствам какие-либо значения по умолчанию, то используются следующие шесть команд: Default, NoDefault, Default для свойств типа массив, Stored, index, Dispid. Например,

Property HumberProp:integer read Fnumber

write FNumber default 5; Property EnumProp: TEnumProp Read FenumProp

write FEnumProp default epOne;.

Для свойства типа массив команда Default указывается после точки с запятой без использования какого-либо значения. Массив, если он задан при объявлении класса, представляет собой начальные значения элементов ин­дексированного свойства.

Property ArrayPropInt[Index: integer]:

string read GetArrayPropInt; Default;.

Команда NoDefault применяется обычно для унаследованных свойств при указании, что родительское значение не действует.

Команда stored используется для того, чтобы указать, сохранять ли те­кущее значение, например,

Property NumProl:integer read Fnuml write FNuml Stored true; Property NumPro2:integer read FNum2 write FNum2 Stored false; Property NumPro3:integer read Fnum3 write Fnum3 Stored Fun3; -


В первом случае указано, что необходимо сохранять текущее значение свойства, во втором - не сохранять, в третьем - сохранять, если функция Fun3 возвращает true.

Команда Index позволяет обеспечить гибкость при объявлении методов доступа Read и write к полям.

Рассмотрим это на примере. Пусть два свойства intProp1 и intProp2 для доступа к полям PIntProp1 и FIntProp2 используют одни и те же под­программы:

Property IntProp1:integer Index 1 read GetIntProp

write SetIntProp;

Property IntProp2:integer Index 2 read GetIntProp

write SetIntProp;.

Для указания того, что свойство IntProp1 работает с полем FIntProp1, a intProp2 - с полем FintProp2, используется команда index. В данном случае число после слова Index указывает, какое поле следует использовать, например, подпрограммы GetIntProp и SetIntProp можно определить так:

Function <имя класса>.GetIntProp (pIndex:integer):integer; begin

case pIndex of

1:result:=FIntProp1; 2:result:=FIntProp2; end; end; Procedure <иия класса>.SetIntProp (pIndex:integer; pValue:integer);

begin

case pIndex of

1: FIntProp1:= pValue;

2: FIntProp2:= pValue;

end; end;.

Команда Dispid применяется при работе с объектами OLE.

ПРИМЕР ПРИЛОЖЕНИЯ 16

Пусть требуется построить на форме три геометрические фигуры: круг, квадрат, эллипс. Необходимо обеспечить возможность изменения цвета ка­ждой фигуры. Пусть будет по два цветовых варианта каждой фигуры (рис. 36).

Для решения задачи построим четыре класса. Первый класс назовем TDrawArea. Включим в него следующие действия: инициализация всех по-


 

read GetBrushColor; procedure DrawFig;virtual;abstract; procedure Drawlt; end; TSquare = class(TDrawArea)
лей, рисование фигуры. Остальные три класса определяют конкретную реa лизацию рисования круга, квадрата и эллипса.


Рис. 36

Программа приводится ниже.

unit PRIM16;




Поделиться с друзьями:


Дата добавления: 2014-12-29; Просмотров: 439; Нарушение авторских прав?; Мы поможем в написании вашей работы!


Нам важно ваше мнение! Был ли полезен опубликованный материал? Да | Нет



studopedia.su - Студопедия (2013 - 2024) год. Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав! Последнее добавление




Генерация страницы за: 0.209 сек.