Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ООП / ООП_Лекции.doc
Скачиваний:
55
Добавлен:
08.06.2015
Размер:
1.03 Mб
Скачать

TObjectи информация о классах

Первое, для чего предназначены ссылки на классы — это получение информации доступа, свойственной для полного класса. Для любой ссылки на класс TClass можно применять любой из методов класса TObject, перечисленных ниже:

• ClassName: возвращает строку с именем класса;

• ClassNameis: проверяет имя класса;

• ClassParent: возвращает ссылку на родительский класс;

• ClassInfo: возвращает указатель на информацию о типе класса во время выполнения программы (Run-Time Type Information — RTTI);

• InheritsFrom: проверяет, наследуется ли класс (прямо или косвенно) из данного базового класса;

• InstanceSize: возвращает размер объектов.

Однако некоторые методы класса TObject — это не методы классов, и поэтому их нельзя применить к ссылке на класс. Один пример — это функция ClassType, возвращающая тип класса.

Регистрация и обнаружение классов

Чтобы использовать методы класса, нам нужна ссылка на объект или класс. Очевидно, что этот класс должен быть доступен нашей программе (класс, для которого включены соответст­вующие модули), и нужно найти общие средства, которые можно использовать для доступа к методам класса. Один способ сделать это заключается в использовании функций FindClass или GetClass, возвращающих ссылку на класс по заданному имени класса. (Хотя и кажется, что эти две функции делают одно и то же, но на самом деле FindClass вызывает исключение, если она не находит имя класса, a GetClass возвращает указатель nil.)

На первый взгляд кажется, что эти функции дают нам именно то, что нужно: правильную ссылку на класс, которую можно использовать для вызова разных методов класса. Однако, необходимо зарегистрировать класс для каждой из этих функций для ее поиска. Это нужно сделать, так как система Delphi должна содержать полное описание того, как строить объекты данного класса в различных ситуациях. Для регистрации используется функция RegisterClass с параметром типа TPersistentClass.

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

type

TClassArray = array[l..140] of TPersistentClass;

const

ClassArray: TClassArray =(

TBitmap, TGraphic, TOutlineNode, TGraphicsObject,

TBrush, THeaderSection, TParams, TCanvas,...

и так далее еще для 132 элементов. Теперь можно использовать этот массив и для регистрации классов, и для заполнения поля со списком:

procedure TForml.FormCreate(Sender: TObject);

var

i: integer;

begin

// регистрация всех классов

RegisterClasses{ClassArray);

// Использование - копирование имен классов в listbox

for i := Low(ClassArray) to High(ClassArray) do

ComboBoxl.Items.Add(ClassArray[i].ClassName);

end;

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

6. Создание объектов во время выполнения, поиск компонентов

Сначала рассмотрим, как создать компонент периода выполнения, например, создание и размещение на форме кнопки:

procedure TForml.ButtonlClick(Sender: TObject);

var

NewButton: TButton;

begin

NewButton:= TButton.Create(self);

NewButton.Name := 'Button2';

NewButton.Left := 100;

NewButton.Top :=100;

NewButton.Parent := self;

End;

Этот код создает новую кнопку, дает ей имя, устанавливает ее позицию в форме и при­сваивает свойство Parent. Имя кнопки должно быть уникальным для данной формы. Каждый элемент управления (не все компоненты, производные только от TControl) должен иметь родителя, то есть компонент, производный от TWindow.

Примечание

Свойства Parent и Owner похожи, но различны. Свойство Parent позволяет компоненту, порожденному из TControl, связываться с его окном. Напротив, свойство Owner устанав­ливается во время вызова конструктора - в данном случае TButton. Create (self) . Свойство Owner определяет, какой компонент ответственен за разрушение другого компонента. В выше­приведенном коде форма является и владельцем и родителем компонента Button. Поэтому окно формы управляет отображением кнопки, и форма уничтожит кнопку, когда приложение уничтожает форму.

Если в программе требуется динамически создавать большое количество разнообразных компонентов, то целесообразно использовать более универсальные приемы, которые способны работать с объектами различных классов.

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

procedure TForml.CreateComponents(X, У: Integer);

var

MyClass: TComponentClass;

MyComp: TComponent;

begin

MyClass := TComponentClass(GetClass(ComboBoxl.Text));

if MyClass = nil then Beep

else begin

MyComp := MyClass.Create(self);

MyComp.Name := GetNextName(MyClass);

if MyClass.InheritsFrom(TControl) then begin

TControl(MyComp).Left:= X;

TControl(MyComp).Top:= Y;

TControl (MyComp) . Parent := self;

end;

UpdateList;

end;

end;

Если исследовать этот код подробнее, то станет понятно, что приведение результата GetClass к классу TComponentClass является опасным. Необходимо убедиться, что все классы в глобальном массиве — действительно классы компонентов. Чтобы гарантировать это, можно временно изменить тип данных массива:

TClassArray = array[1..133] of TComponentClass;

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

Далее обратите внимание, что в этой функции свойство Name компонента установлено с использованием возвращаемого значения метода GetNextName. Этот метод ищет массив формы Components, подсчитывает число компонентов данного типа, уже существующих в форме, а затем добавляет это число в конец класса имени компонента (без начальной буквы "Т"), чтобы построить уникальное имя компонента внутри формы:

function TForml.GetNextName(MyClass: TComponentClass): string;

var

I, nTot: Integer;

begin

nTot := 0;

for I := 0 to ComponentCount - 1 do

if Components[I].ClassType = MyClass then Inc(nTot);

Result := Copy(MyClass.ClassHame, 2,

Length(MyClass.ClassName) - 1) + IntToStr(nTot);

end;

После установки свойства Name определяется позиция и родительское окно компонента, но только в том случае, если этот визуальный компонент -элемент управления. Обратите внимание на проверку:

if MyClass.InheritsFrom(TControl) then

Необходимо выполнить проверку этим способом, потому что оператор is неправомерен для проверки типа ссылки на класс. Конечно, проверку можно изменить следующим способом:

if MyComp is TControl then

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

procedure TForrnl. UpdateList;

var

I: Integer;

begin

ComboBox2.Items.Clear;

for I:= 0 to ComponentCount - 1 do

ComboBox2.Items.Add(Components[I].Name);

end;

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

Соседние файлы в папке ООП