Выбор базового класса
Приступая к разработке нового компонента, следует четко сформулировать назначение компонента. Затем необходимо определить, какой из компонентов Delphi наиболее близок по своему назначению, виду и функциональным возможностям к компоненту, который разрабатывается. Именно этот компонент следует выбрать в качестве базового.
Создание модуля компонента
Перед началом работы по созданию нового компонента нужно создать отдельный каталог для модуля и других файлов компонента. После этого можно приступить к созданию модуля компонента.
Для того чтобы создать модуль компонента, необходимо из меню Component выбрать команду New Component и в поля открывшегося диалогового окна New Component (рис. 16.1) ввести информацию о создаваемом компоненте.
Рис. 16.1. Диалоговое
окно New Component
В поле Class Name необходимо ввести имя класса разрабатываемого компонента, например TNkEdit. Вспомните, что в Delphi имена типов должны начинаться буквой т.
В поле Palette Page нужно ввести имя вкладки палитры компонентов, на которую после создания компонента будет добавлен его значок. Название вкладки палитры компонентов можно выбрать из раскрывающегося списка. Если в поле Palette Page ввести имя еще не существующей вкладки палитры компонентов, то непосредственно перед добавлением компонента вкладка с указанным именем будет создана.
В поле Unit, file name находится автоматически сформированное имя файла модуля создаваемого компонента. Delphi присваивает модулю компонента имя, которое совпадает с именем типа компонента, но без буквы T. Щелкнув на кнопке с тремя точками, можно выбрать каталог, в котором должен быть сохранен модуль компонента.
После нажатия кнопки ОК к текущему проекту добавляется сформированный Delphi-модуль, представляющий собой заготовку (шаблон) модуля компонента. Текст этого модуля приведен в листинге 16.1.
Листинг 16.1.
Шаблон модуля компонента
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
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
После создания формы в модуль приложения, автоматически сформированный Delphi, необходимо внести следующие дополнения:
1. В список используемых модулей (раздел uses) добавить имя модуля тестируемого компонента (NkEdit).
2. В раздел объявления переменных (var) добавить инструкцию объявления компонента. Здесь следует вспомнить, что компонент является объектом, поэтому объявление компонента в разделе переменных не обеспечивает создание компонента, а только генерирует указатель на компонент, следовательно необходима инструкция вызова конструктора объекта, которая действительно создает компонент (объект).
3. Для формы приложения создать процедуру обработки события oncreate, которая вызовом конструктора тестируемого компонента создаст компонент и установит значения его свойств.
В листинге 16.3 приведен модуль приложения тестирования компонента NkEdit.
Листинг 16.3.
Тест компонента NkEdit
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
Поле Search path (Путь поиска) должно содержать разделенные точкой с запятой имена каталогов, в которых Delphi во время установки компонента будет искать необходимые файлы, в частности файл ресурсов компонента. Если имя файла модуля было введено в поле Unit file name выбором файла из списка, полученного при помощи кнопки Browse, то Delphi автоматически добавляет в поле Search path имена необходимых каталогов.
Примечание
Поле Package file name должно содержать имя пакета, в который будет установлен компонент. По умолчанию компоненты, создаваемые программистом, добавляются в пакет Dclusr70.dpk.Файл ресурса компонента должен находиться в одном из каталогов, перечисленных в поле Search path. Если его там нет, то компоненту будет назначен значок его родительского класса.
Поле Package description содержит название пакета. Для пакета Dclusr70.dpk
ЭТО текст: Borland User's Components.
После заполнения перечисленных полей и нажатия кнопки ОК начинается процесс установки. Сначала на экране появляется окно Confirm (рис. 16.5), в котором Delphi просит подтвердить обновление пакета.
Рис. 16.5. Запрос
подтверждения обновления пакета в процессе установки компонента
Рис. 16.6. Сообщение
о неуспешной установке компонента
Рис. 16.7. Окно
редактора пакета компонентов
Рис. 16.8. Вкладка Samples после установки компонента NkEdit
Ошибки при установке компонента
Во время работы над новым компонентом наиболее частой ошибкой является попытка установить (переустановить) компонент, который уже находится в одном из пакетов (обычно такое желание возникает после внесения изменений в модуль компонента).
В этом случае Delphi выводит сообщение: The package already contains unit named... (Пакет уже содержит модуль, который называется...) и процесс установки завершается. Для того чтобы преодолеть эту ошибочную ситуацию и установить компонент в нужный пакет или установить в пакет обновленную версию компонента, необходимо сначала удалить компонент из пакета, а затем установить его снова.
Тестирование компонента
После того как компонент будет добавлен в пакет, необходимо проверить поведение компонента во время разработки приложения, использующего этот компонент (работоспособность компонента была проверена раньше, когда он добавлялся в форму приложения динамически, во время работы программы).
Можно считать, что компонент работает правильно, если во время разработки приложения удалось поместить этот компонент в форму разрабатываемого приложения и, используя окно Object Inspector, установить, значения свойств компонента, причем как новых, так и унаследованных от родительского класса.
Работоспособность компонента NkEdit можно проверить, использовав его, например, в приложении Поездка на дачу, вид формы которого приведен на рис. 16.9.
Рис. 16.9. Форма
приложения Поездка на дачу (поля ввода-редактирования компонента
NkEdit)
Рис. 16.10. Свойство
компонента NkEdit отражено в окне Object Inspector
Листинг 16.4.
Приложение "Поездка на дачу" тест компонента
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. Выбор
пакета для редактирования
Рис. 16.12. Диалоговое
окно Confirm
Рис. 16.13. Окно
редактора пакета
Рис. 16.14. Выбор
компонента, удаляемого из пакета
Рис. 16.15. Информационное
сообщение о том, что компонент больше недоступен
Настройка палитры компонентов
Delphi позволяет менять порядок следования вкладок палитры компонентов, названия вкладок, а также порядок следования значков компонентов на вкладках. Настройка палитры компонентов выполняется в диалоговом окне Palette Properties, которое открывается выбором из меню Component команды Configure Palette (рис. 16.16).
Рис. 16.16. Диалоговое
окно Palette Properties
Если надо изменить порядок следования значков компонентов на вкладке, то в списке Components следует выбрать нужный значок компонента и кнопками Move Up и Move Down переместить значок на новое место.
При необходимости изменить имя вкладки палитры следует в списке Pages выбрать имя нужной вкладки, нажать кнопку Rename и в поле Page name открывшегося диалогового окна Rename page (рис. 16.17) ввести новое имя.
Рис. 16.17. Диалоговое окно Rename page