#ifndef OurComponentH
#define OurComponentH
#include <SysUtils. hpp>
#include <Classes. hpp>
class PACKAGE TOurComponent : public TComponent
{private:
protected:
public:
__fastcall TOurComponent(TComponent* Owner);
__published:};
#endif
Вместе с заголовочным файлом будет создан файл OurComponent. cpp
#include <basepch. h>
#pragma hdrstop
#include "OurComponent. h"
#pragma package(smart_init)
static inline void ValidCtrCheck(TOurComponent *)
{ new TOurComponent(NULL); }
__fastcall TOurComponent::TOurComponent(TComponent* Owner)
: TComponent(Owner){ }
namespace Ourcomponent
{ void __fastcall PACKAGE Register()
{TComponentClass classes[1] = {__classid(TOurComponent)};
RegisterComponents("OurSamples", classes, 0);}}
Как видно из приведенного примера создается заготовка для конструктора, а также определяются две функции ValidCtrCheck и Register. Функция ValidCtrCheck необходима для проверки наличия в создаваемом компоненте чистых виртуальных функций. Данная функция будет вызвана при установке компонента. В ней просто производится попытка создания экземпляра компонента, что в случае наличия чистой виртуальной функции приведет к генерации ошибки и отмене инсталляции. Функция Register регистрирует компонент в палитре компонентов. В первом параметре указывается имя закладки в палитре компонент, второй - параметр-массив указателей на метаклассы регистрируемых компонент, третий содержит количество регистрируемых компонентов минус 1.
Для компонента может быть создана пиктограмма, которая будет отображаться в палитре компонентов. Для этого необходимо использовать Image Editor из пункта главного меню Tools. В этом редакторе необходимо выбрать пункт File | New | Component Resource File (.dcr), а затем пункт Resource | New | Bitmap и задать размер 24х24 пиксела. Необходимо переименовать созданный Bitmap, назвав его так же, как и будущий класс компонента, но заглавными буквами. Для нашего случая это будет имя TOURCOMPONENT. Далее можно нарисовать необходимый рисунок, учитывая, что цвет левого нижнего квадрата будет считаться прозрачным. Сам файл ресурса необходимо сохранить в том же каталоге, что и файлы. cpp и. h, с тем же именем, но с расширением. dcr. Для нашего случая это будет имя ourcomponent. dcr. После внесения изменений в файлы. cpp и. h можно приступать к установке нового компонента. Для этого необходимо выбрать пункт главного меню Component | Install Component и в появившемся окне в поле “Unit file name” указать имя. cpp файла, содержащего исходный код компонента. В поле “Packege File Name” выбрать пакет, в который будет помещен компонент. По умолчанию пользовательские компоненты помещаются в пакет “Borland User Components”. После нажатия кнопки “Ok” необходимо согласиться с перекомпиляцией пакета и сохранить изменения в пакете. После этого новый компонент появится в палитре компонентов той закладки, которая была указана при регистрации компонента. Для удаления/добавления или перекомпиляции модулей в пакетах можно также использовать пункт Component | Install Package. В появившемся окне необходимо выбрать нужный пакет и нажать кнопку «Edit».
8.2. Определение свойств и событий компонента
В рассмотренном выше примере была создана всего лишь заготовка компонента. В реальной ситуации программист должен реализовать некоторый код, обеспечивающий функциональность нового компонента. Принцип работы с новым компонентом ничем не отличается от обычной процедуры наследования ООП. Таким образом, программист может определять новые компонентные данные или функции, а также использовать наследуемые. Новым в среде С++Builder является возможность использования свойств и событий. Как уже отмечалось, свойства предоставляют дополнительный интерфейс для доступа к защищенным данным класса. События позволяют определить реакцию на изменение состояния компонента. Свойства и события могут быть определены в одной из стандартных областей видимости класса (private, protected, public), в этом случае их доступность определяется также как и для данных класса. Однако в среде С++Builder введена еще одна директива для области видимости __published. Если свойство или событие будет размещено в этой секции, то оно будет доступно в инспекторе объектов на этапе проектирования. Для описания свойств и событий используется ключевое слово __property. Описание свойств и событий в общем случае выглядит следующим образом
__property <type> <id> { read = <data/function id>, write = <data/function id>}
Кроме атрибутов read и write для свойств можно устанавливать дополнительные атрибуты, которые также называются спецификаторами свойств, однако их рассмотрение выходит за рамки данного учебного пособия. <id> определяет имя свойства и задается по стандартным правилам для идентификаторов С++. Согласно нотации среды С++Builder имена событий начинаются с букв “On”. Описание свойств и событий отличаются только типом <type>. События должны иметь специальный тип «событие», указатель на функцию, описанный с ключевым словом __closure. Видя такой тип, инспектор объектов размещает события на закладке Events. Свойства могут иметь любой стандартный или производный тип, доступный для переменных. При использовании классов VCL необходимо использовать тип указатель на класс, поскольку статические экземпляры классов VCL не допустимы. Кроме того, в этом случае необходимо создать экземпляр класса в конструкторе и уничтожить его в деструкторе. Присваивание переменных, содержащих указатели на класс, необходимо осуществлять с помощью метода Assign. Свойства на самом деле не хранят никаких данных и являются как бы интерфейсом для доступа к внутренним данным компонента. Где на самом деле будут храниться данные, и как будет происходить доступ к ним, определяется с помощью спецификаторов read и write. И read, и write могут указывать и на метод, и на переменную (обычно объявленную в private секции класса). Чаще всего write указывает на функцию, а read просто на переменную. В самой функции также происходит запись значения в переменную, однако использование функции позволяет реализовать дополнительные возможности, например, проверку допустимых значений при записи в свойство или изменение значения других свойств и переменных в зависимости от данного. Имя свойства может не иметь ничего общего с именем переменной, которую оно модифицирует. Однако согласно нотации среды С++Builder имя связанной со свойством должно быть таким же, как и имя свойства, но с префиксом F. Если write отсутствует, то свойство будет только для чтения (но значение переменной, на которую оно указывает, может быть изменено какими-либо другими способами, например из других методов класса). Как уже отмечалось, события позволяют определить пользователю компонента собственный обработчик событий. Обработчик события представляет собой обычную функцию класса (обычно принадлежащую классу формы), в которую передается указатель на объект, который сгенерировал события и некоторые дополнительные данные, специфичные для каждого типа события. Если произошло какое-либо событие, то компонент просто вызывает назначенный этому событию обработчик, таким образом позволяя пользователю компонента выполнить необходимые действия при возникновении этого события. Рассмотрим пример определения свойств и событий.
Заголовочный .h файл
class PACKAGE TOurComponent : public TComponent
{private:
int FMyInteger; char FMyChar;
Graphics::TFont *FMyFont;
TNotifyEvent FOnMyError;
void __fastcall SetMyInteger(const int Value);
__published:
__property int MyInteger = {read=FMyInteger, write=SetMyInteger};
__property char MyChar = {read=FMyChar, write=FMyChar};
__property Graphics::TFont* MyFont = {read=FMyFont, write=SetMyFont};
__property TNotifyEvent OnMyError = {read=FOnMyError, write=FOnMyError};}
Исходный. cpp файл
__fastcall TOurComponent::TOurComponent(TComponent* Owner)
: TComponent(Owner)
{FMyInteger=10;FMyChar='s';
FMyFont= new Graphics::TFont();}
__fastcall TOurComponent::~TOurComponent()
{delete FMyFont;}
void __fastcall TOurComponent::SetMyFont(const Graphics::TFont *Value)
{ FMyFont->Assign((TPersistent*)Value); }
void __fastcall TOurComponent::SetMyInteger(const int Value)
{if (Value%2) FMyInteger = Value;
else if (!ComponentState. Contains(csDesigning))
if (FOnMyError) FOnMyError (this);}
В данном примере определяется три свойства: MyChar, MyFont и MyInteger. Свойство MyChar обеспечивает доступ к защищенной переменной FMyChar без каких-либо дополнительных возможностей. Свойство MyFont обеспечивает доступ к защищенной переменной FMyFont, являющейся указателем на класс типа TFont. Еще раз отметим, что в этом случае объект должен быть создан в конструкторе и уничтожен в деструкторе. Кроме того, как видно из функции SetMyFont, значение переменной FMyFont присваивается с помощью метода Assign. Данный метод обеспечит корректное копирование всех внутренних данных и свойств класса TFont. При выполнении же присваивания вида FMyFont=Value произойдет присваивание указателей. В результате мы потерям доступ к блоку памяти, выделенному ранее под FMyFont, и при удалении объекта Value, указатель FMyFont станет некорректным. Свойство MyInteger обеспечивает доступ к защищенной переменной FMyInteger. При чтении значения свойства происходит просто чтение этой переменной, при записи же происходит проверка: для записи в переменную доступны лишь четные значения. При попытке же записи нечетного значения будет сгенерировано событие FOnMyError, причем генерация события происходит, только если компонент находится на этапе выполнения, а не на этапе проектирования. Для проверки на каком этапе находится компонент, можно использовать свойство ComponentState: если это свойство содержит флаг csDesigning, то компонент находится на этапе проектирования. Далее происходит проверка, назначил ли программист, использующий наш компонент, обработчик события OnMyError. Поскольку переменная FOnMyError содержит адрес функции обработчика, то, если программист не назначил обработчик, в ней будет содержаться значение NULL. В противном случае происходит вызов назначенной функции обработчика, при этом в качестве параметра передается указатель this, т. е. указатель на текущий экземпляр класса, для которого была вызвана функция SetMyInteger. В обработчике этот параметр будет доступен как указатель Sender, что позволит программисту определить в обработчике, какой именно экземпляр класса вызвал данное событие.
Вывод
Среда С++Builder предоставляет удобные средства для создания пользовательских компонент. Работа с созданными компонентами ничем не отличается от работы со стандартными, и они позволяют существенно расширить функциональность среды С++Builder.
Список литературы
1. Я. Разработка прикладных программ для Windows в С++ Builder 5- М.: БИНОМ», 2000. – 256 с.:ил.
2. З., П. Введение в BorlandC++Builder – М.:Диалог-МИФИ, 1998. – 272 с.
3. Рихтер Дж. Windows для профессионалов (программирование в Win32 API для Windows NT 4.0 и Windows 95) / Пер. с англ. – М.: Издательский отдел “Русская редакция” ТОО “Chanel Trading Ltd.”, 1997. – 720 c.:ил.
4. Borland C++Builder: библиотека программиста – СПб: Питер Ком, 1998. – 512с.: ил.
5. Холингворт Дж., Borland C++Builder 6. Руководство разработчика.: Пер. с англ. – М.: Издательский дом «Вильямс», 2004. – 976 с.:ил.
6. А. Borland C++ Builder. Программирование на С++ без проблем. М.: «Нолидж», 1997. – 266 с., ил.
Дмитрий Николаевич Лясин
Сергей Геннадьевич Саньков
Основы программирования в среде C++Builder
Учебное пособие
П. Чеботарева
План заказных изданий 2007г. поз. N 1
Лицензия ИД N04790 от 01.01.2001
Подписано в печать _________ . Формат 60 х 84
Бумага газетная. Печать офсетная. Усл. печ. л. ____ .
Уч. -изд. л. ___ . Тираж _____ . Заказ _____ .
Волгоградский государственный технический университет.
400131 Волгоград, пр. Ленина, 28.
РПК "Политехник" Волгоградского государственного технического
университета.
400131 Волгоград, ул. Советская, 35.
|
Из за большого объема этот материал размещен на нескольких страницах:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
Основные порталы (построено редакторами)
