ГЛАВА 7

- Основы создания компонентов
- Выбор предка компонента
- Создание заготовки компонента
- Статические методы
- Виртуальные методы
- Динамические методы
  - Методы-сообщения
- Замещенные методы
- Абстрактные методы

Данная глава посвящена творческому процессу создания собственных компонентов. Мы рассмотрим различные способы разработки новых компонентов, научимся строить свои невизуальные компоненты.
Основы создания компонентов
Итак, мы приступаем к процессу создания собственного визуального или невизуального компонента. Для создания собственного компонента важно иметь представление о библиотеке визуальных компонентов Delphi, об иерархии компонентов. Все это мы уже рассматривали выше. Для чего же нужны новые компоненты? Ответ неоднозначный. Решение о создании но вых компонентов может быть принято по ряду причин, среди которых:
- разработка нового пользовательского интерфейса, с дальнейшим использованием его в других приложениях;
- создание принципиально нового класса, которого нет в стандартной библиотеке Delphi и среди элементов ActiveX;
- упрощение кода приложения, путем введения новых компонентов; - распространение своих компонентов среди других программистов;
- и, наконец, желание глубоко изучить Delphi, разобраться с тонкостями программирования.
Естественно, кроме упомянутых причин, вы можете назвать множество собственных. Создание компонентов по сложности практически не отличается от разрабокти приложений. Конечно, все зависит от сложности компонента. Но если вы уже решились на сотворение компонента, рекомендации будут следующими:
- определите для себя, какие действия должен выполнять компонент; - разработайте краткий алгоритм, по которому будет работать компонент;
- разбейте всю конструкцию компонента на независимые части;
- предоставьте возможность дальнейшей разработки компонента (возможно, в будущем вы захотите создать на его основе компонент-потомок);
- напишите код компонента (этот пункт разбивается на такие этапы):
выбор предка для вашего компонента;
создание заготовки (модуля) компонента;
создание свойств, событий и методов компонента;
отладка и тестирование;
регистрация компонента в среде Delphi;
создание справки для вашего компонента. Далее мы рассмотрим перечисленные выше этапы создания компонента.
Выбор предка компонента
Итак, вы уже знаете основные классы, имеющиеся в VCL Delphi. Ранее мы рассмотрели базовые классы, которые могут являться предками вашего компонента (см. главу 6). Эти классы перечислены в табл. 2.9.
Таблица 2.9. Базовые классы VCL

| Класс | Возможности класса |
| TObject | Классы, предком которых является данный класс, не являются компонентами. Класс TObject применяется при создании объектов, которые, обычно, являются предками для других компонентов |
| TComponent | Применяется для создания невизуальных компонентов |
| TGraphicControl | Применяется для создания не оконных компонентов, т. е. компонентов без дескриптора окна. Потомки данного класса размещаются в клиентской области своих родительских компонентов и не требуют системных ресурсов |
| TWinControl | Применяется для создания компонентов, имеющих дескриптор окна. Данные компоненты являются компонентами оконного типа и могут содержать в себе другие компоненты |
| TCustomControl | Этот класс является потомком TWinControl и дополняет его областью вывода (канвой). В данный класс добавлен метод Paint. Рекомендуется использовать настоящий класс для создания пользовательских оконных компонентов |
| TCustomClassName | Библиотека визуальных компонентов содержит несколько классов, у которых не все свойства объявлены как published, т. е. доступные из других модулей, но на основе данных классов можно создавать классы-потомки, в которых и объявлять данные свойства. Таким образом, разработчик может создать несколько идентичных классов на основе одного класса ClassName и в каждом из этих классов определять необходимые свойства из набора предопределенных свойств |
| TComponentName | Позволяет создавать компоненты-потомки, предками которых являются обычные компоненты или классы VCL Delphi. Таким образом, если перед разработчиком стоит задача расширить возможности какого-либо компонента Delphi, можно использовать данный класс |

Обратите внимание на то, что для правильного выбора класса-предка, вам нужно очень хорошо ориентироваться в возможностях уже существующих в Delphi классов.
Создание заготовки компонента
Итак, вы выбрали класс-предок для вашего компонента. Теперь можно приступать к созданию модуля вашего компонента. Создание модуля (заготовки) для нового компонента можно выполнить путем вызова окна Delphi, которое называется экспертом компонентов (Component Expert). Данное окно можно вызвать путем выбора в главном меню Delphi пункта Component/New Component (Компонент/Новый компонент). При этом появляется окно, изображенное на рис. 2.13.
Рис. 2.13. Окно эксперта компонентов
Рассмотрим данное окно подробнее. Итак, поле ввода Ancestor type предназначено для ввода класса-предка для нового компонента. Это поле ввода содержит в выпадающем списке все зарегистрированные классы библиотеки VCL. Предположим, что мы будем создавать компонент, предком которого является кнопка TButton. Для этого выберем в выпадающем списке класс TButton. Поле Class Name предназначено для ввода имени нового класса. Пусть в нашем случае это будет новый класс TMyButton. Заметьте, что по умолчанию Delphi заполняет это поле именем класса-предка с добавлением порядкового номера (в нашем случае TButtoni). Еще одно поле Palette Page показывает, на какой вкладке палитры компонентов будет расположен новый компонент после его регистрации. Оставим в этом поле значение, предлагаемое Delphi по умолчанию samples. Два следующих поля Unit file name и Search path заполняются средой Delphi самостоятельно, но разработчик может их изменить. Мы не будем этого делать в нашем примере. В результате окно эксперта компонентов должно быть заполнено так, как показано на рис. 2.14.
Рис. 2.14. Заполненное окно эксперта компонентов
После заполнения полей данного окна нажимаем кнопку ОК, и Delphi автоматически создаст заготовку модуля вашего компонента. Модуль заготовки для нашего примера представлен на листинге 2.7.
Листинг 2.7
unit MyButton;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls; type
TMyButton = class(TButton)
private
{ Private declarations }
protected
{ Protected declarations } public
{ Public declarations } published
{ Published declarations } end;
procedure Register; implementation procedure Register; begin
RegisterComponents('Samples', [TMyButton]); end;
end.
Итак, заготовка для нового компонента готова. Она не содержит никаких новых свойств, методов и событий для создаваемого компонента. Нужно отметить, что данный компонент уже имеет все свойства, события и методы, которые определены для класса TButton. Мы уже кратко рассматривали процедуру создания нового класса (см. раздел "Объектно-ориентированное программирование" главы 1). Там же мы обсуждали основные типы свойств класса. Обратим теперь взор на основные типы методов компонента.
Все методы могут быть одного из нескольких типов: статические (static), виртуальные (virtual), динамические (dynamic) или методы-сообщения (message). По умолчанию, методу присваивается статический тип.
Статические методы
Статические методы аналогичны обычным функциям или процедурам Delphi. Адрес такого метода известен среде Delphi на стадии компиляции, поэтому Delphi производит статический вызов метода во время выполнения программы. Статические методы работают быстрее всех других методов, но не могут быть перегружены (overload).
Перегрузка метода подразумевает, что класс или компонент может содержать несколько методов с одинаковым именем, но разными списками параметров.
Статический метод может быть описан так:
type
TComponent = class
procedure MyProcedure;
end;
Здесь, метод MyProcedure является статическим. Мы опустили в данном примере название базового класса TObject после слова class. По умолчанию, компилятор создает наследников класса TObject.
Виртуальные методы
Виртуальные методы, в отличие от статических, поддерживают перегрузку, поэтому вызов таких методов для среды Delphi намного сложнее (заранее неизвестен адрес конкретного вызываемого метода). Для того чтобы решить эту проблему, Delphi строит таблицу виртуальных методов (Virtual Method Table), благодаря которой компилятор может определить адрес метода во время выполнения программы. Эта таблица содержит виртуальные методы не только самого класса или компонента, но и его предков. Естественно, хранение такой таблицы увеличивает расходы памяти, но вызов виртуальных методов выполняется быстрее, чем вызов динамических методов.
Описание виртуального метода выглядит следующим образом:
type
TComponent = class
procedure MyProcedure; virtual;
end;
В данном случае метод MyProcedure - виртуальный.
Динамические методы
Динамические методы похожи на виртуальные, они также могут быть перегружены. Основная разница между виртуальными и динамическими методами - в способе их вызова. Если для виртуальных методов строится таблица виртуальных методов, то каждому динамическому методу присваивается уникальное число-идентификатор, после чего строится таблица динамических методов (Dynamic Method Table), в которую заносится данное число, а также адрес метода. Еще одно отличие динамических методов от виртуальных заключается в том, что таблицы динамических методов содержат методы только одного компонента или класса (не включая его предков). Поэтому существенно экономится память, но замедляется время работы, т. к. для поиска адреса метода обычно приходится просматривать несколько таблиц динамических методов.
Описание динамического метода может выглядеть так:
type
TComponent = class
procedure MyProcedure; dynamic;
end;
Методы-сообщения
Методы-сообщения не вызываются из программы непосредственно, как другие методы. Этот тип методов предназначен для того, чтобы выполнить какие-либо действия в ответ на сообщение Windows. В качестве примера рассмотрим описание метода-сообщения:
type
TComponent = class
procedure MyProcedure(Var A: TMessage); message wm_MessageWindows;
end;
После служебного слова message ставится значение (в нашем случае wmjfessagewindows), определяющее сообщение Windows, в ответ на которое будет вызванан метод MyProcedure.
Виртуальные и динамические методы могут быть замещенными (overriden) или абстрактными (abstract).
Замещенные методы
Замещение методов предполагает передачу и изменение методов от компонента (класса) предка компоненту (классу) наследнику. Как мы уже отметили, только виртуальные или динамические методы могут быть замещенными. Рассмотрим пример:
type
TComponentChild = class (TComponentParent)
procedure MyProcVirtual; override;
procedure MyProcDynamic; override;
end;
Применение служебного слова override после названия метода позволяет заместить оригинал метода компонента предка методом компонента наследника. При этом замещение происходит непосредственно в таблице виртуальных методов (или таблице динамических методов). При использовании
Служебных слов virtual или dynamic вместо override, произойдет просто создание нового метода вместо замещения старого.
Замещение методов не работает со статическими методами - при замещении статического метода новым произойдет простая замена метода родителя в потомке.
Абстрактные методы
Абстрактными могут быть виртуальные или динамические методы. Абстрактными методами называются такие методы, которые описаны внутри определения класса или компонента, но не содержат никаких действий и никогда не вызываются. Такие методы используются только в компонентах или классах-предках. Описание абстрактного метода выглядит так:
procedure MyProcedure; virtual; abstract;
Примечание
Никогда не вызывайте на выполнение абстрактные методы, т. к. они не содержат никаких команд, которые могли бы выполниться. Вызов абстрактного метода приведет к генерации исключительной ситуации EAbstractError.
О создании свойств, методов и событий новых компонентов расскажет следующая глава этой книги.

Глава 6 Содержание Глава 8