Рассказывается о возможности Delphi предоставлять в создать программисту свой собственный компонент, поместить его на одну из вкладок палитры компонентов и использовать при разработке приложений точно так же, как и другие компоненты Delphi.
Компонент
программиста
Delphi предоставляет
возможность программисту создать свой собственный компонент, поместить его на
одну из вкладок палитры компонентов и использовать при разработке приложений
точно так же, как и другие компоненты Delphi.
Процесс создания компонента
может быть представлен как последовательность следующих этапов:
1. Выбор базового класса.
2. Создание модуля
компонента.
3. Тестирование компонента.
4. Добавление компонента
в пакет компонентов.
Рассмотрим процесс создания компонента программиста на примере разработки компонента NkEdit, предназначенного для ввода и редактирования дробного числа.
Выбор
базового класса
Приступая к разработке нового компонента, следует четко сформулировать назначение компонента. Затем необходимо определить, какой из компонентов Delphi наиболее близок по своему назначению, виду и функциональным возможностям к компоненту, который разрабатывается. Именно этот компонент следует выбрать в качестве базового.
Создание
модуля компонента
Перед началом работы
по созданию нового компонента нужно создать отдельный каталог для модуля и других
файлов компонента. После этого можно приступить к созданию модуля компонента.
Для того чтобы создать
модуль компонента, необходимо из меню Component выбрать команду New Component
и в поля открывшегося диалогового окна New Component (рис.
16.1) ввести информацию о создаваемом компоненте.

Рис. 16.1. Диалоговое
окно New Component
Поле Ancestor type
должно содержать базовый тип для создаваемого компонента. Базовый тип компонента
можно задать непосредственным вводом имени типа или выбором из раскрывающегося
списка. Для разрабатываемого компонента базовым компонентом является стандартный
компонент Edit (поле ввода-редактирования). Поэтому базовым типом для типа разрабатываемого
компонента является тип TEdit.
В поле Class Name
необходимо ввести имя класса разрабатываемого компонента, например TNkEdit.
Вспомните, что в Delphi имена типов должны начинаться буквой т.
В поле Palette Page
нужно ввести имя вкладки палитры компонентов, на которую после создания
компонента будет добавлен его значок. Название вкладки палитры компонентов можно
выбрать из раскрывающегося списка. Если в поле Palette Page ввести имя
еще не существующей вкладки палитры компонентов, то непосредственно перед добавлением
компонента вкладка с указанным именем будет создана.
В поле Unit, file
name находится автоматически сформированное имя файла модуля создаваемого
компонента. Delphi присваивает модулю компонента имя, которое совпадает с именем
типа компонента, но без буквы T. Щелкнув на кнопке с тремя точками, можно выбрать
каталог, в котором должен быть сохранен модуль компонента.
После нажатия кнопки
ОК к текущему проекту добавляется сформированный Delphi-модуль, представляющий
собой заготовку (шаблон) модуля компонента. Текст этого модуля приведен в листинге
16.1.
Листинг 16.1.
Шаблон модуля компонента
unit
NkEdit; interface
uses
Windows,
Messages, SysUtils, Classes, Controls, StdCtrls;
type
TEdit1
= class(TEdit)
private
{
Private declarations }
protected
{
Protected declarations }
public
{
Public declarations }
published
{
Published declarations }
end;
procedure
Register;
implementation
procedure Register;
begin
RegisterComponents('Samples',
[TNkEdit]);
end;
end.
В объявлении нового
класса указан только тип родительского класса. В раздел реализации помещена
процедура Register, которая используется во время установки созданного программистом
компонента на указанную вкладку палитры компонентов Delphi для регистрации нового
класса.
В сформированное Delphi
объявление класса нового компонента нужно внести дополнения: объявить свойство,
поле данных этого свойства, функцию доступа к полю данных, процедуру установки
значения поля данных, конструктор и деструктор. Если на некоторые события компонент
должен реагировать не так, как базовый, то в объявление класса нужно поместить
описание соответствующих процедур обработки событий.
В листинге 16.2 приведен
текст модуля компонента NkEdit после внесения всех необходимых изменений.
Листинг 16.2.
Модуль компонента NkEdit
unit NkEdit;
interface
uses
Windows,
Messages, SysUtils,
Classes, Graphics, Controls,
Forms, Dialogs, StdCtrls;
type
TNkEdit
= class(TEdit)
private
FNumb:
single; // число, находящееся в поле редактирования
//
Это описание функции доступа
//
и процедуры установки поля FNumb
function
GetNumb: single;
procedure
SetNumb(value:single);
protected
procedure
KeyPress(var Key: Char);
override;
public
published
constructor
Create(AOwner:TComponent);
override; property Numb : single
// свойство компонента
read GetNumb write SetNumb;
end;
procedure
Register;
implementation
//
процедура регистрации компонента
procedure
Register;
begin
RegisterComponents('Samples',[TNkEdit]);
end;
//
конструктор компонента
constructor
TNkEdit.Create(AOwner:TComponent);
begin
//
don't forget to call the ancestors' constructor
inherited
Create(AOwner);
end;
//
функция доступа к полю FNumb
function TNkEdit.GetNumb:single;
begin
try
// поле Text может быть пустым Result:=StrToFloat(text); except
on
EConvertError do begin
Result:=0;
text: =' ' ;
end;
end;
end;
//
процедура записи в поле FNumb
procedure TNkEdit.SetNumb(Value:single);
begin
FNumb:=Value;
Text:=FloatToStr(value);
end;
//
процедура обработки события KeyPress
procedure TNkEdit.KeyPress(var key:char) ;
begin
case
key of
'0'..
'9', #8, #13: ;
'-':
if Length(text)<>0 then key:=#0;
else
if
not ((key = DecimalSeparator) and
(Pos(DecimalSeparator,text)=0))
then key:= #0;
end;
inherited
KeyPress(key);
//
вызов процедуры обработки события
//
OnKeyPress родительского класса
end;
end.
В описание класса TNkEdit
добавлено объявление свойства Numb, которое представляет собой число, находящееся
в поле редактирования. Для хранения Значения свойства Numb используется поле
FNumb. Функция GetNumb необходима для доступа к полю FNumb, а процедура setNumb
— для установки значения свойства.
Конструктор класса
TNkEdit сначала вызывает конструктор родительского класса (TEdit), присваивает
значение свойству Text, затем устанавливает значение свойства Numb.
Реакция компонента
NkEdit на нажатие клавиши клавиатуры определяется процедурой обработки события
TNkEdit.KeyPress, которая замещает соответствующую процедуру базового класса.
В качестве параметра процедура TNkEdit.KeyPress получает код нажатой клавиши.
Перед вызовом процедуры обработки события OnKeyPress родительского класса код
нажатой клавиши проверяется на допустимость. Если нажата недопустимая для компонента
NkEdit клавиша, то код символа заменяется на ноль. Допустимыми для компонента
NkEdit являются цифровые клавиши, разделитель целой и дробной частей числа (в
зависимости от настройки Windows: точка или запятая), "минус", <Backspase>
(позволяет удалить ошибочно введенный символ) и <Enter>.
Здесь следует вспомнить,
что в тексте программы дробная часть числовой константы отделяется от целой
части точкой. Во время работы программы при вводе исходных данных пользователь
должен использовать тот символ, который задан в настройке Windows. В качестве
разделителя обычно применяют запятую (это для России стандартная настройка)
или точку. Приведенная процедура обработки события OnKeyPress учитывает, что
настройка Windows может меняться, и поэтому введенный пользователем символ сравнивается
не с константой, а со значением глобальной переменной
DecimalSeparator, которая содержит символ-разделитель, используемый в Windows
в данный момент.
После ввода текста модуля компонента модуль нужно откомпилировать и сохранить.
Тестирование
модуля компонента
Перед добавлением нового
компонента в палитру компонентов необходимо всесторонне его проверить. Для этого
надо создать приложение, использующее компонент и убедиться, что компонент работает
так, как надо.
Во время создания формы
приложения нельзя добавить в форму компонент, значка которого нет в палитре
компонентов. Однако такой компонент может быть добавлен в форму динамически,
т. е. во время работы приложения.
Создается тестовое
приложение обычным образом: сначала создается форма приложения, а затем — модуль
приложения.
Вид формы приложения
тестирования компонента NkEdit- приведен на рис. 16.2.
Рис. 16.2. Форма
приложения Тест компонента NkEdit
Форма содержит две
метки и командную кнопку. Первая метка предназначена для вывода информационного
сообщения, вторая метка (на рисунке она выделена) используется для вывода числа,
введенного в поле редактирования. Самого поля редактирования компонента NkEdit
в форме нет. Этот компонент будет создан динамически во время работы программы,
но для него оставлено место над полем метки.
После создания формы
в модуль приложения, автоматически сформированный Delphi, необходимо внести
следующие дополнения:
1. В список используемых
модулей (раздел uses) добавить имя модуля тестируемого компонента (NkEdit).
2. В раздел объявления
переменных (var) добавить инструкцию объявления компонента. Здесь следует вспомнить,
что компонент является объектом, поэтому объявление компонента в разделе переменных
не обеспечивает создание компонента, а только генерирует указатель на компонент,
следовательно необходима инструкция вызова конструктора объекта, которая действительно
создает компонент (объект).
3. Для формы приложения
создать процедуру обработки события oncreate, которая вызовом конструктора тестируемого
компонента создаст компонент и установит значения его свойств.
В листинге 16.3 приведен
модуль приложения тестирования компонента NkEdit.
Листинг 16.3.
Тест компонента NkEdit
unit
tstNkEdit_; interface
uses
Windows,
Messages, SysUtils,
Variants, Classes, Graphics,
Controls,Forms,
Dialogs, StdCtrls,
NkEdit;
// ссылка на модуль компонента
type
TForm1
= class(TForm)
Label1:
TLabel;
Label2:
TLabel;
Buttonl:
TButton;
procedure
FormCreate(Sender: TObject);
procedure
ButtonlClick(Sender: TObject);
private
{
Private declarations }
public
{
Public declarations }
end;
var
Form1:
TForm1;
myEdit:
TnkEdit; // компонент NkEdit
implementation
{$R
*.dfm)
procedure
TForm1.FormCreate(Sender: TObject);
begin
//
создадим компонент и поместим его на форму
myEdit
:= TNkEdit.Create(self);
myEdit.Parent := self;
myEdit.Left := 8;
myEdit.Top := 64;
end;
procedure
TForm1.ButtonlClick(Sender: TObject);
begin
label2.
Caption := FloatToStr (myEdit .Numb) ;
end;
end.
Тестируемый компонент
создается процедурой обработки события Formcre-ate (Создание формы) посредством
вызова конструктора компонента, которому в качестве параметра передается значение
self, показывающее, что владельцем компонента является форма приложения.
После создания компонента
обязательно должен быть выполнен важный шаг: свойству Parent необходимо присвоить
значение. В данном случае тестируемый компонент находится в форме приложения,
поэтому свойству Parent присваивается значение self.
На рис. 16.3 приведено
окно программы Тест компонента NkEdit во время ее работы, после ввода
числа в поле редактирования и щелчка на кнопке Тест.
Рис. 16.3. Тестирование компонента. Поле ввода — компонент NkEdit
Установка
компонента
Для того чтобы значок
компонента появился в палитре компонентов, компонент должен быть добавлен в
один из пакетов (Packages) компонентов
Delphi. Пакет компонентов
— это файл с расширением dpk (Delphi Package File). Например, компоненты, созданные
программистом, находятся в пакете Dclusr70.dpk.
Во время добавления компонента в пакет Delphi использует модуль компонента и файл ресурсов компонента, в котором должен находиться битовый образ значка компонента. Имя файла ресурсов компонента должно обязательно совпадать с именем файла модуля компонента. Файл ресурсов имеет расширение dcr (Dynamic Component Resource). Битовый образ, находящийся внутри файла ресурсов, должен иметь имя, совпадающее с именем класса компонента.
Ресурсы
компонента
Файл ресурсов компонента
можно создать при помощи утилиты Image Editor, которая запускается выбором из
меню Tools команды Image Editor.
Для того чтобы создать
новый файл ресурса компонента, нужно из меню File выбрать команду New
и из появившегося списка выбрать тип создаваемого файла — Component Resource
File.
В результате открывается
окно файла ресурсов Untitledl.dcr, а в меню диалогового окна Image Editor
появляется новый пункт — Resource. Теперь нужно
из меню Resource выбрать команду New/Bitmap и в открывшемся окне
Bitmap Properties установить характеристики битового образа значка компонента:
Size — 24x24 пиксела, Colors — 16.
В результате этих действий
в создаваемый файл ресурсов компонента будет добавлен новый ресурс — битовый
образ с именем Bitmap1 Двойной щелчок на имени ресурса (Bitmapl) раскрывает
окно редактора битового образа, в котором можно нарисовать нужную картинку.
Изображение в окне
графического редактора можно увеличить. Для этого необходимо выбрать команду
Zoom In меню View.
Следует обратить внимание,
что цвет правой нижней точки рисунка определяет "прозрачный" цвет.
Элементы значка компонента, закрашенные этим цветом, на палитре компонентов
Delphi не видны.
Перед тем, как сохранить
файл ресурсов компонента, битовому образу надо присвоить имя. Имя должно совпадать
с именем класса компонента. Чтобы задать имя битового образа, необходимо щелкнуть
правой кнопкой мыши на имени битового образа (Bitmap1), выбрать в появившемся
контекстном меню команду Rename и ввести новое имя.
Созданный файл ресурсов
компонента нужно сохранить в том каталоге, в котором находится файл модуля компонента.
Для этого надо из меню File выбрать команду Save.
Внимание!
Имя файла ресурсов компонента (Edit.dcr) должно совпадать с именем модуля компонента (Edit.pas), а имя битового образа (Edit) — с именем класса компонента (Edit).
Установка
После создания файла
ресурсов компонента, в котором находится битовый образ значка компонента, можно
приступить к установке компонента. Для этого надо из меню Component выбрать
команду Install Component и заполнить поля открывшегося окна Install
Component (рис. 16.5).

Рис. 16.4. Диалоговое
окно Install Component
В поле Unit file
name нужно ввести имя файла модуля. Для этого удобно воспользоваться кнопкой
Browse.
Поле Search path
(Путь поиска) должно содержать разделенные точкой с запятой имена каталогов,
в которых Delphi во время установки компонента будет искать необходимые файлы,
в частности файл ресурсов компонента. Если имя файла модуля было введено в поле
Unit file name выбором файла из списка, полученного при помощи кнопки
Browse, то Delphi автоматически добавляет в поле Search path имена
необходимых каталогов.
Примечание
Файл ресурса компонента должен находиться в одном из каталогов, перечисленных в поле Search path. Если его там нет, то компоненту будет назначен значок его родительского класса.
Поле Package file
name должно содержать имя пакета, в который будет установлен компонент.
По умолчанию компоненты, создаваемые программистом, добавляются в пакет Dclusr70.dpk.
Поле Package description
содержит название пакета. Для пакета Dclusr70.dpk
ЭТО текст: Borland
User's Components.
После заполнения перечисленных
полей и нажатия кнопки ОК начинается процесс установки. Сначала на экране
появляется окно Confirm (рис. 16.5), в котором Delphi просит подтвердить
обновление пакета.
Рис. 16.5. Запрос
подтверждения обновления пакета в процессе установки компонента
После нажатия кнопки
Yes процесс установки продолжается. Если он завершается успешно, то на
экране появляется информационное сообщение (рис. 16.6) о том, что в результате
обновления пакета палитра компонентов обновлена, т. е. в нее добавлен значок
компонента, и новый компонент зарегистрирован.
Рис. 16.6. Сообщение
о неуспешной установке компонента
После установки компонента
в пакет открывается диалоговое окно Package (Редактор пакета компонентов)
(рис. 16.70), в котором перечислены компоненты, находящиеся в пакете.

Рис. 16.7. Окно
редактора пакета компонентов
На этом процесс установки
компонента заканчивается. В результате на вкладке палитры компонентов, имя которой
было задано при создании модуля компонента, появляется значок установленного
компонента (рис. 16.8).
Рис. 16.8. Вкладка Samples после установки компонента NkEdit
Ошибки
при установке компонента
Во время работы над
новым компонентом наиболее частой ошибкой является попытка установить (переустановить)
компонент, который уже находится в одном из пакетов (обычно такое желание возникает
после внесения изменений в модуль компонента).
В этом случае Delphi выводит сообщение: The package already contains unit named... (Пакет уже содержит модуль, который называется...) и процесс установки завершается. Для того чтобы преодолеть эту ошибочную ситуацию и установить компонент в нужный пакет или установить в пакет обновленную версию компонента, необходимо сначала удалить компонент из пакета, а затем установить его снова.
Тестирование
компонента
После того как компонент
будет добавлен в пакет, необходимо проверить поведение компонента во время разработки
приложения, использующего этот компонент (работоспособность компонента была
проверена раньше, когда он добавлялся в форму приложения динамически, во время
работы программы).
Можно считать, что
компонент работает правильно, если во время разработки приложения удалось поместить
этот компонент в форму разрабатываемого приложения и, используя окно Object
Inspector, установить, значения свойств компонента, причем как новых, так
и унаследованных от родительского класса.
Работоспособность компонента
NkEdit можно проверить, использовав его, например, в приложении Поездка на
дачу, вид формы которого приведен на рис. 16.9.
Рис. 16.9. Форма
приложения Поездка на дачу (поля ввода-редактирования компонента
NkEdit)
Внешне форма разрабатываемого приложения почти ничем не отличается от формы приложения Поездка на дачу, рассмотренного в гл. 6. Однако если выбранным компонентом будет поле ввода, то в окне Object Inspector указано, что текущим компонентом является компонент класса TNkEdit, a в списке свойств можно увидеть новое (по сравнению со списком свойств стандартного компонента Edit) свойство — Numb (рис. 16.10).
Рис. 16.10. Свойство
компонента NkEdit отражено в окне Object Inspector
В листинге 16.4 приведен
модуль приложения Поездка на дачу. Очевидно, что текст программы значительно
меньше первоначального варианта, в котором для ввода данных использовался компонент
Edit.
Листинг 16.4.
Приложение "Поездка на дачу" тест компонента
unit fazenda
;
interface
uses
Windows,
Messages, SysUtils,
Variants,
Classes, Graphics, Controls,
Forms,
Dialogs, StdCtrls,
NkEdit;
// ссылка на модуль компонента
type
TForm1
= class(TForm)
NkEdit
1: TNkEdit; //расстояние
NkEdit2:
TNkEdit; // цена литра бензина
NkEditS:
TNkEdit; // потребление бензина на 100 км
CheckBox1:
TCheckBox; // True — поездка туда и обратно
Button1:
TButton; Label4: TLabel;
Label1: TLabel; Label2: TLabel;
Label3:
TLabel;
//
кнопка Вычислить
//
поле вывода результата расчета
procedure
ButtonlClick(Sender: TObject);
procedure
NkEditlKeyPress
(Sender:
TObject; var Key: Char);
procedure
NkEdit2KeyPress
(Sender:
TObject; var Key: Char);
procedure
NkEditSKeyPress
(Sender: TObject; var Key: Char);
private
{
Private declarations }
public
{
Public declarations }
end;
var
Form1:
TForm1;
implementation
{$R
*.dfm}
//
нажатие клавиши в поле Расстояние
procedure
TForm1.NkEdit1KeyPress
(Sender:
TObject; var Key: Char);
begin
if
Key = Char(VK_RETURN)
then
NkEdit2.SetFocus; // переместить курсор в поле Цена
end;
//
нажатие клавиши в поле Цена
procedure
TForm1.NkEdit2KeyPress
(Sender:
TObject; var Key: Char);
begin
if
Key = Char(VK_RETURN)
then
NkEdit3.SetFocus;
// переместить курсор в поле Потребление
end;
//
нажатие клавиши в поле Потребление
procedure
TForm1.NkEdit3KeyPress
(Sender:
TObject; var Key: Char);
begin
if
Key = Char(VK_RETURN)
then
Buttonl.SetFocus; //
// сделать активной кнопку Вычислить
end;
//
щелчок на кнопке Вычислить
procedure
TForml.ButtonlClick(Sender: TObject);
var
rast
: real; // расстояние
cena
: real; // цена
potr
: real; // потребление на 100 км
summ
: real; // сумма
mes:
string; begin
rast
:= StrToFloat(NkEdit1.Text);
cena
:= StrToFloat(NkEdit2.Text);
potr
:= StrToFloat(NkEdit3.Text) ;
summ
:= rast / 100 * potr * cena;
if
CheckBoxl.Checked then sunnm := summ * 2;
mes
:= 'Поездка на дачу';
if
CheckBoxl.Checked then mes := mes + ' и обратно';
mes
:= mes + 'обойдется в '
+
FloatToStrF(summ,ffGeneral,4,2) + ' руб.';
Label4.Caption
:= mes;
end;
end.
Удаление
компонента
Иногда возникает необходимость
удалить компонент из пакета. Сделать это можно при помощи редактора пакета компонентов.
Для того чтобы запустить
редактор пакета компонентов, надо из меню Component выбрать команду Install
Packages, в открывшемся диалоговом окне Project Options (рис. 16.11)
из списка Design packages выбрать нужный пакет и нажать кнопку Edit.
Рис. 16.11. Выбор
пакета для редактирования
В открывшемся окне
Confirm (рис. 16.12) в ответ на запрос: cancel this dialog box and open...
(Закрыть этот диалог и открыть пакет...) надо нажать кнопку Yes.
Рис. 16.12. Диалоговое
окно Confirm
В результате открывается
окно редактора пакета Package (рис. 16.13), в котором в списке Contains
(Содержимое) перечислены компоненты пакета.
Рис. 16.13. Окно
редактора пакета
Для того чтобы удалить
компонент из пакета, необходимо нажать кнопку Remove. В открывшемся диалоговом
окне Remove From Project (рис. 16.14) следует выбрать удаляемый компонент
и нажать кнопку ОК.
Рис. 16.14. Выбор
компонента, удаляемого из пакета
После удаления компонента из пакета нужно обязательно выполнить перекомпиляцию пакета. Для этого необходимо в окне редактора пакета нажать кнопку Compile. После перекомпиляции пакета Delphi информирует о том, что удаленный компонент больше не зарегистрирован (рис. 16.15).

Рис. 16.15. Информационное
сообщение о том, что компонент больше недоступен
После перекомпиляции пакета необходимо закрыть окно редактора пакета и в открывшемся окне подтвердить сохранение изменений в пакете, из которого был удален компонент.
Настройка
палитры компонентов
Delphi позволяет менять
порядок следования вкладок палитры компонентов, названия вкладок, а также порядок
следования значков компонентов на вкладках. Настройка палитры компонентов выполняется
в диалоговом окне Palette Properties, которое открывается выбором из
меню Component команды Configure Palette (рис. 16.16).
Рис. 16.16. Диалоговое
окно Palette Properties
Сначала в списке Pages
необходимо выделить нужную вкладку палитры компонентов. Затем, если надо
изменить порядок следования вкладок палитры компонентов, следует воспользоваться
кнопками Move Up и Move Down и путем перемещения выбранного имени по
списку Pages добиться нужного порядка следования вкладок.
Если надо изменить
порядок следования значков компонентов на вкладке, то в списке Components
следует выбрать нужный значок компонента и кнопками Move Up и Move Down
переместить значок на новое место.
При необходимости изменить
имя вкладки палитры следует в списке Pages выбрать имя нужной вкладки,
нажать кнопку Rename и в поле Page name открывшегося диалогового
окна Rename page (рис. 16.17) ввести новое имя.
Рис. 16.17. Диалоговое окно Rename page
