Тебе предстоит познакомится с технологией создания собственных компонентов. Я
расскажу, как можно создать компонент Delphi (не путай с компонентами ActiveX).
В качестве примера я выбрал достаточно простой, но напичканый математикой пример
- часы. Наши часы смогут работать как аналоговые и числовые. По этим часам будет
Москва сверятся :).
Компоненты - это самая удобная вещь. С самого появления языков
программирования, все программеры стремятся добится многократности использования
кода. Для этого мы перешли к процедурному программирования, затем к объектному и
сейчас нам предлагают перейти к компонентному программированию. То, что
предлагает нам MS - использовать компоненты ActiveX я назову настоящей лажей.
Эти компоненты требую гемороя для регистрации их на машине клиента, слежка за
версиями и многое другое. Borland предложила свои компоненты. По умолчанию они
встраиваются прямо в запускной файл и не требуют никакой регистрации и
великолепно работают.
Я думаю, что я достаточно расхвалил компоненты Delphi, пора бы и написать
один для примерчика.
Для создания нового компонента выбери меню Component-> New Component.
Давай расмотрим каждое окошечко в отдельности:
- Ancestor type - Тип предка. Это имя объекта, от
которого мы порадим наш объект. Это даст нашему объекту все
возможности его предка, плюс мы добавим свои. Для часиков нам
понадобится TGraphicControl.
- Class Name - Имя нашего будущего компонента. Я его
назвал TGraphicClock.
- Palette Page - Имя палитры компонентов, куда будет
помещён наш компонент после инсталляции. Я оставил значение по
умолчанию "Samples". Но ты можешь поместить его даже на закладку
"Standart".
- Unit file name - имя и путь к модулю, где будет
располагатся исходный код компонента. Хотябы посмотри под каким
именем сохранят твой компонент и где.
- Search path - Сюда можно даже не заглядывать.
Жмём "ОК" (именно "ОК", а не Install) и получаем созданный Дульфой код:
unit GraphicClock;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs;
type
TGraphicClock = class(TGraphicControl)
private
{ Private declarations }
protected
{ Protected declarations }
public
{ Public declarations }
published
{ Published declarations }
end;
procedure Register;
implementation
procedure Register;
begin
RegisterComponents('Samples', [TGraphicClock]);
end;
end.
В принципе простейший компонент готов и его можно инсталировать в Дельфу. Но
этот компонент ничего не умеет и он пока является полным аналогом своего предка
TGraphicControl. Чтобы он стал отличатся, сейчас мы добавим ему разные свойства.
Начнём написание нашего компонента с конструктора и деструктора. конструктор
- это простая процедура, которая автоматически вызывается при создании
компонента. Деструктор - тоже процедура, только она автоматически вызывается при
уничтожении компонента. В конструкторе мы проинициализируем все наши переменные,
а в деструкторе уничтожим.
Итак, напиши в разделе public:
constructor Create(AOwner: TComponent); override;
Теперь нажми сочетание клавишь CTRL+SHIFT+C. Дельфи сам создаст заготовку для
конструктора:
constructor TGraphicClock.Create(AOwner: TComponent);
begin
inherited;
end;
Поправим её до вот такого вида:
constructor TCDClock.Create(AOwner: TComponent);
begin
//Вызываем конструктор предка
inherited Create(AOwner);
//Устанавливаем значения ширины и высоты по умолчанию
Width := 50;
Height := 50;
//Устанавливаем переменную ShowSecondArrow в true.
//Она будет у нас отвечать за показ секундной стрелки
ShowSecondArrow := true;
//Инициализируем остальные переменные
PrevTime := 0;
CHourDiff := 0;
CMinDiff := 0;
//Инициализируем растры TBitmap, в которых будут хранится
//фон и сам рисунок часов.
FBGBitmap:= TBitmap.Create;
FFont:=TFont.Create;;
FBitmap:= TBitmap.Create;
FBitmap.Width := Width;
FBitmap.Height := Height;
//Выставляем формат времени
DateFormat:='tt';
//Запускаем таймер
Ticker := TTimer.Create( Self);
//Интервал работы таймера - одна секунда
Ticker.Interval := 1000;
//По событию OnTimer будет вызыватсья процедура TickerCall
Ticker.OnTimer := TickerCall;
//Включаем таймер
Ticker.Enabled := true;
//Устанавливаем цвета поумолчанию
FFaceColor := clBtnFace;
FHourArrowColor := clActiveCaption;
FMinArrowColor := clActiveCaption;
FSecArrowColor := clActiveCaption;
end;
Ключевое слово inherited вызывает конструктор предка (в нашем случае
TGraphicClock). В остальном, я надеюсь, что с конструктором всё ясно.
Теперь создадим деструктор. Для этого также опишем его в разделе public:
public
{ Public declarations }
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
Кстати, ключевое слово override; после имени этих процедур говорит о
том, что мы хотим переписать уже существующую у предка функцию с таким именем.
Теперь жмём Ctrl+Shift+C и получаем заготовку для деструктора и поправляем её до
вида :
destructor TGraphicClock.Destroy;
begin
Ticker.Free;
FBitmap.Free;
FBGBitmap.Free;
inherited Destroy;
end;
Заметь, что в конструкторе я вызывал предка в самом начале inherited, а в
деструкторе в самом конце. В конструкторе сначала нужно, чтобы
проинициализировался предок (он проинициализирует необходимые ссылки), а потом
можно инициализировать свои вещи. Если в деструкторе мы сначала вызовем предка,
то последующая работа с компонентом уже будет невозможна, потому что предок
уничтожит все ссылки, поэтому я ставлю этот вызов в конце.
Теперь опишем все необходимые нам переменные в разделе private:
private
//Для часов обязательно понадобится таймер
Ticker: TTimer;
//Картинки часов и фона
FBitmap, FBGBitmap: TBitmap;
/События
FOnSecond, FOnMinute, FOnHour: TNotifyEvent;
//Центральная точка
CenterPoint: TPoint;
//Радиус
Radius: integer;
//Остальные параметры, которые мы рассмотрим в процессе.
LapStepW: integer;
PrevTime: TDateTime;
ShowSecondArrow: boolean;
FHourArrowColor,FMinArrowColor, FSecArrowColor: TColor;
FFaceColor: TColor;
CHourDiff, CMinDiff: integer;
FClockStyle:TClockStyle;
FDateFormat: String;
FFont: TFont;
Теперь в разделе private опицем процедуру TickerCall. Мы её уже использовали
в конструкторе. Она у нас вызывается по событию от таймера:
protected
{ Protected declarations }
procedure TickerCall(Sender: TObject);
Жмём CTRL+SHIAT+C и модифицируем созданную функцию:
procedure TCDClock.TickerCall(Sender: TObject);
var
H,M,S,Hp,Mp,Sp: word;
begin
//Если компонент создан в дезайнере, то выход
if csDesigning in ComponentState then exit;
//Иначе это уже запущеная программа
//Получить время
DecodeCTime( Time, H, M, S);
//Получить предыдущее время.
DecodeCTime( PrevTime, Hp, Mp, Sp);
//Сгенерировать событие OnSecond
if Assigned( FOnSecond) then FOnSecond(Self);
//Сгенерировать событие OnMinute
if Assigned( FOnMinute) AND (Mp < M) then FOnMinute(Self);
//Сгенерировать событие OnHour
if Assigned( FOnHour) AND (Hp < H) then FOnHour(Self);
//Сохранить текущее время в PrevTime
PrevTime := Time;
if ( NOT ShowSecondArrow) AND (Sp <= S) then exit;
//Прорисовать часы.
DrawArrows;
end;
DrawArrows напичкана математикой и она сейчас не имеет для нас особого
значения. Немного ниже я приведу её в полном исходнике, а сейчас я просто
расказываю тебе о том, как создавать компонента, поэтому мы рассмотрим сабытия
генерируемые в функции TickerCall.
У нас уже объявлено три события:
FOnSecond, FOnMinute, FOnHour: TNotifyEvent;
Все они появятся на закладке Events в окне Object Inspector, когда ты
поставишь компонент на форму. Чтобы приложения могло поймать эти события, мы
объявили переменные типа TNotifyEvent и генерируем эти события (с помощью
конструкции типа FOnSecond(Self) для события OnSecond), когда изменилась
секунда, изменилась минута или изменился час.
Помимо этого, в разделе published мыдолжны описать свойство OnSecond:
property OnSecond: TNotifyEvent read FOnSecond write FOnSecond;
property OnMinute: TNotifyEvent read FOnMinute write FOnMinute;
property OnHour: TNotifyEvent read FOnHour write FOnHour;
Теперь наш компонент сможет генерировать события.
С событиями вроде всё ясно (если нет, то посмотри на исходник в конце
статьи). Теперь переходим к свойствам. В разделе published мы можем создавать
свойства, которые будут отображатся в Object Inspector при выделении наших
часиков. Все свойства, которые есть у предка нужно просто описать
published
property Align;
property Enabled;
property ParentShowHint;
property ShowHint;
property Visible;
Слово property говорит о том, что мы описываем свойство. Для них не нужны
процедуры или функции, потому что эти свойства уже есть у предка. Нам надо
только описать их и всё. Я описал только маленькую часть из доступных у
TGraphicControl функций. Ты можешь добавить любые из доступных. Чтобы узнать,
какие функции можно добавлять, открой помощь (меню Help->Delphi Help) и найди
там объект TGraphicControl. Щёлкни по нему дважды и в появившейся справке выбери
пункт Properties (вверху окна) (рис 2). Появится окно с перечнем всех свойств.
Ты можешь добавить любое из них. Например, чтобы добавить свойство Action нужно
написать в разделе published:
published
property Action;
Чтобы добавить своё свойство, нужно немного попатеть. Например. Добавим
возможность, чтобы пользователь мог менять картинку фона. Для этого описываем в
разделе published свойство BGBitmap:
//свойство Имя :Тип читать из FBGBitmap записывать с помощью SetBGBitmap
property BGBitmap:TBitmap read FBGBitmap write SetBGBitmap;
Коментарий поможет тебе разобраться в написанном здесь. Итак, мы объявили
свойство BGBitmap типа ТBitmap. Для чтения используется простая переменная
FBGBitmap (можно использовать и функцию, но нет смысла, потому что можно прямо
читать из переменной), для записи используется процедура SetBGBitmap. Процедура
выглядит так:
procedure TCDClock.SetBGBitmap(Value: TBitmap);
begin
FBGBitmap.Assign(Value);
invalidate;
end;
Теперь ты можешь изменять фон простой операцией
GraphicClock1.BGBitmap:=bitmap.
Если ты хочешь создать свойство с выпадающим списком (как например у свойства
Align), по щелчку которого выпадает список возможных параметров, то тут уже
немного сложнее. В моих часах есть такой параметр, который делает выбор, какого
типа будут часы - аналоговые или цыфровые. Объявление делается так:
//свойство Имя :Тип Это нам известно Значение по умолчанию
property ClockStyle:TClockStyle read FClockStyle write SetStyleStyle default scAnalog;
Мы объявляем свойство ClockStyle типа TClockStyle. Тип TClockStyle мы должны
описать в самом начале, до описания нашего объекта TGraphicClock:
type
TClockStyle = (scAnalog, scDigital);
TGraphicClock = class(TGraphicControl)
private
Ticker: TTimer;
Строка TClockStyle = (scAnalog, scDigital) - объявляет список переменных,
которые и будут выпадать по выбору свойства.
Всё остально происходит так же, за исключением нового слова default
Которое устанавливает значение по умолчанию - scAnalog.
Вот и всё, что я хотел тебе рассказать.
Чтобы установить компонент в системе нужно щёлкнуть меню Component->Install
Component. Перед тобой появится окно.
В строке Unit file name нужно указать полный путь к файлу. Для
облегчения выбора используй кнопку Browse
справа. Перед тобой появится запрос на компиляцию пакета. Соглашайся.
В этом окне ты можешь откомпелировать пакет с помощью кнопки Compile и
установить в Delphi с помощью Install .
Вот и всё. Наслаждайся новым компонентом в твоей палитре.
На сегодня хватит. Статья и так получилась достаточно большая. Увидимся в
следующий раз.
Напоследок у меня есть небольшая просьба. Пиши мне, о чём бы ты хотел
прочитать на моих страницах. Некоторые разделы я неуспеваю писать, а некоторые я
просто уже не знаю, о чём тебе рассказать. Ты просто пиши мне, а там разберёмся.
|